【Android】【Compose】实现列表数据添加

news2024/12/23 6:27:58
序言

在使用列表的时候,以前是使用 Layout 布局里面添加Recyclerview进行列表的显示,但是在Compose里面,是没有这个Recyclerview使用的,那Compose怎么实现列表数据呢?

使用 【LazyColumn】

首先创建一个Compose项目

在创建Compose项目的时候,有时候会创建失败,因为使用的各种配置文件和Android studio版本可能导致的不兼容问题,出现各种意外情况。

我使用的Android studio版本是
在这里插入图片描述
在创建项目之后,配置文件如下,这样是可以正常运行的,用来学习Compose的使用方式是足够了。

setting.gradle

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
    }
}
rootProject.name = "MyCompose"
include ':app'

项目下的gradle文件

buildscript {
    ext {
        compose_version = '1.0.1'
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.2"
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21'

    }
}


task clean(type: Delete) {
    delete rootProject.buildDir
}

app下面的gradle文件

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 30

    defaultConfig {
        applicationId "com.example.mycompose"
        minSdk 23
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
        useIR = true
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
        kotlinCompilerVersion '1.5.21'
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.activity:activity-compose:1.3.0-alpha06'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}

gradle目录下的 wrapper文件夹下面的 gradle-wrapper.properties文件

distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

里面的版本不高,但是挺适合相应的Android studio版本的

在使用Recyclerview进行列表加载的时候,是需要创建一个数据bean的,在使用Compose的时候也不例外

创建一个数据Bean

data class Item(val id: Int, val name: String)

项目运行截图
在这里插入图片描述
项目运行代码

class ListActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyComposeTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = Color.Green
                ) {
                    DynamicItemsList()
                }
            }
        }
    }
}

@Composable
fun DynamicItemsList() {
    val items by remember { mutableStateOf(mutableStateListOf<Item>()) }

    fun addItem() {
        val newItem = Item(id = items.size + 1, name = "Item ${items.size + 1}")
        items.add(newItem)
    }

    Column(
        Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Button(onClick = { addItem() }, modifier = Modifier.fillMaxWidth()) {
            Text(text = "ADD Item")
        }
        Spacer(modifier = Modifier.height(10.dp))
        LazyColumn(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.White)
        ) {
            items(items) { item ->
                ItemView(item = item)
            }
        }
    }
}

@Composable
fun ItemView(item: Item) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
            .background(Color.LightGray)
            .border(2.dp, color = Color.Red)
            .height(50.dp),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = item.name,
            style = MaterialTheme.typography.body1,
            fontSize = 14.sp
        )
    }
}

分析一下代码

//ComponentActivity 是一个基础活动类,提供了与用户界面的相关功能,例如生命周期管理和设置视图等。它是 Jetpack Compose 的一个活动基类。
class ListActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //setContent 是 Jetpack Compose 的一个方法,用于设置 Compose 的内容。它接受一个 Composable 函数作为参数,这个函数定义了 UI 的组成部分。
        setContent {
        //MyComposeTheme 是一个自定义的主题函数,用于定义 Compose 应用的主题和样式。它通常会包含对颜色、形状、字体等主题属性的定义。使用主题函数可以确保应用的 UI 风格一致,并且可以通过主题轻松地调整样式。
            MyComposeTheme {
            //Surface 是一个 Compose 组件,用于绘制具有背景颜色和边界的矩形区域。它通常用于为 UI 元素提供背景和边框。
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = Color.Green
                ) {
                    DynamicItemsList()
                }
            }
        }
    }
}

Surface 源码

@Composable
fun Surface(
    modifier: Modifier = Modifier,
    shape: Shape = RectangleShape,
    color: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(color),
    border: BorderStroke? = null,
    elevation: Dp = 0.dp,
    content: @Composable () -> Unit
) {
    Surface(
        modifier = modifier,
        shape = shape,
        color = color,
        contentColor = contentColor,
        border = border,
        elevation = elevation,
        content = content,
        clickAndSemanticsModifier = Modifier
            .semantics(mergeDescendants = false) {}
            .pointerInput(Unit) { }
    )
}

modifier:用于修饰组件的外观和行为,默认为 Modifier(即没有任何修饰)。
shape:定义组件的形状,默认为 RectangleShape(矩形)。
color:定义组件的背景色,默认为 MaterialTheme.colors.surface(主题的表面颜色)。
contentColor:定义组件的内容颜色,默认为基于 color 计算得到的值。
border:可选的边框样式,默认为 null(没有边框)。
elevation:组件的阴影高度,默认为 0.dp(没有阴影)。
content:接收一个 Composable 函数作为参数,用于定义组件内部的内容。

这个 Surface 是Android Compose自带的,但是 DynamicItemsList 是我们自己自定义的

@Composable
fun DynamicItemsList() {
    val items by remember { mutableStateOf(mutableStateListOf<Item>()) }

    fun addItem() {
        val newItem = Item(id = items.size + 1, name = "Item ${items.size + 1}")
        items.add(newItem)
    }

    Column(
        Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Button(onClick = { addItem() }, modifier = Modifier.fillMaxWidth()) {
            Text(text = "ADD Item")
        }
        Spacer(modifier = Modifier.height(10.dp))
        LazyColumn(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.White)
        ) {
            items(items) { item ->
                ItemView(item = item)
            }
        }
    }
}

这个 DynamicItemsList 里面的这个 ItemView 也是我们自定义的

@Composable
fun ItemView(item: Item) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
            .background(Color.LightGray)
            .border(2.dp, color = Color.Red)
            .height(50.dp),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = item.name,
            style = MaterialTheme.typography.body1,
            fontSize = 14.sp
        )
    }
}

在Compose中,要是自定义一个Compose函数,需要满足:

1.使用 @Composable 注解:标记函数为 Composable 函数,使其能够用于声明式 UI 构建。
2.函数参数:可以包含需要的参数来定义组件的外观和行为。参数通常包括修饰符、颜色、形状等。
3.函数体:在函数体中调用其他 Composable 函数来构建 UI。

例如,定义一个简单的自定义按钮组件:

@Composable
fun CustomButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    backgroundColor: Color = Color.Blue,
    content: @Composable () -> Unit
) {
    Button(
        onClick = onClick,
        modifier = modifier,
        colors = ButtonDefaults.buttonColors(backgroundColor = backgroundColor),
        content = content
    )
}

在这个示例中:

1.@Composable 标记函数为 Composable。
2.CustomButton 接收 onClick 回调、修饰符、背景色和内容作为参数。
3.函数体内部使用 Button Composable 函数构建实际的 UI 元素,并应用传入的参数。

回到项目代码里面,在这个 ItemView 函数里面

@Composable
//ItemView 函数接受一个 Item 类型的参数,用于传递要显示的数据。
fun ItemView(item: Item) {
//Box 是一个容器 Composable,用于排列其子组件。
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
            .background(Color.LightGray)
            .border(2.dp, color = Color.Red)
            .height(50.dp),
        contentAlignment = Alignment.Center
    ) {
    //Text 用于显示文本内容。
        Text(
            text = item.name,
            style = MaterialTheme.typography.body1,
            fontSize = 14.sp
        )
    }
}

其中里面用到了 Text 和 Box两个函数

Text

@Composable
fun Text(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current
) {
    Text(
        AnnotatedString(text),
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        emptyMap(),
        onTextLayout,
        style
    )
}

text: String:要显示的文本内容。
modifier: Modifier = Modifier:用于修饰和布局组件的 Modifier,默认为 Modifier。
color: Color = Color.Unspecified:文本颜色,默认为 Color.Unspecified 表示不设置颜色。
fontSize: TextUnit = TextUnit.Unspecified:文本字体大小,默认为 TextUnit.Unspecified 表示不设置。
fontStyle: FontStyle? = null:字体样式,默认为 null 表示不设置。
fontWeight: FontWeight? = null:字体粗细,默认为 null 表示不设置。
fontFamily: FontFamily? = null:字体家族,默认为 null 表示使用默认字体。
letterSpacing: TextUnit = TextUnit.Unspecified:字母间距,默认为 TextUnit.Unspecified 表示不设置。
textDecoration: TextDecoration? = null:文本装饰(如下划线),默认为 null 表示不设置。
textAlign: TextAlign? = null:文本对齐方式,默认为 null 表示不设置。
lineHeight: TextUnit = TextUnit.Unspecified:行高,默认为 TextUnit.Unspecified 表示不设置。
overflow: TextOverflow = TextOverflow.Clip:文本溢出处理方式,默认为 TextOverflow.Clip。
softWrap: Boolean = true:是否启用软换行,默认为 true。
maxLines: Int = Int.MAX_VALUE:最大行数,默认为 Int.MAX_VALUE,表示不限制行数。
onTextLayout: (TextLayoutResult) -> Unit = {}:文本布局完成后的回调函数,默认为空函数。
style: TextStyle = LocalTextStyle.current:文本样式,默认为当前主题的文本样式。

Box

@Composable
inline fun Box(
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    propagateMinConstraints: Boolean = false,
    content: @Composable BoxScope.() -> Unit
) {
    val measurePolicy = rememberBoxMeasurePolicy(contentAlignment, propagateMinConstraints)
    Layout(
        content = { BoxScopeInstance.content() },
        measurePolicy = measurePolicy,
        modifier = modifier
    )
}

modifier: Modifier = Modifier

Modifier 是用于修饰和布局组件的类。默认值是 Modifier,即不进行任何额外修饰。

contentAlignment: Alignment = Alignment.TopStart

控制 Box 内部内容的对齐方式。Alignment.TopStart 表示默认的内容对齐方式是顶部开始(即左上角)。

propagateMinConstraints: Boolean = false

如果为 true,Box 会将其最小尺寸约束传播给子组件。默认值为 false,即不会传播最小约束。

content: @Composable BoxScope.() -> Unit

这是一个 Composable Lambda,用于定义 Box 内部的子组件内容。BoxScope 是一个作用域,在 content 中可以访问。

接下来是我们定义的另一个函数 DynamicItemsList

@Composable
fun DynamicItemsList() {
//items:这是一个可变的状态列表,使用 mutableStateListOf 创建。by remember 确保状态在组合过程中保持一致。
//mutableStateListOf<Item>():创建一个可以观察的、可变的 List。这意味着,当列表的内容发生变化时,Compose 会自动重新组合相关的 UI 部分。

//mutableStateOf(...):包装 mutableStateListOf,使其成为一个状态对象。Compose 能够检测到 mutableStateOf 包装的对象的变化,从而重新组合 UI。

//remember { ... }:在组合过程中记住 mutableStateOf 返回的状态对象,确保状态在重组时保持一致。

//val items by ...:使用 by 委托将 items 绑定到状态对象。这样,items 就是一个直接的、可读写的可变状态列表。
    val items by remember { mutableStateOf(mutableStateListOf<Item>()) }

//addItem:创建一个新的 Item 对象并将其添加到 items 列表中。id 和 name 基于列表的大小生成。
    fun addItem() {
        val newItem = Item(id = items.size + 1, name = "Item ${items.size + 1}")
        items.add(newItem)
    }
//Column:垂直布局容器
    Column(
        Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
    //Button按钮
        Button(onClick = { addItem() }, modifier = Modifier.fillMaxWidth()) {
            Text(text = "ADD Item")
        }
        //Spacer添加垂直间隔。
        Spacer(modifier = Modifier.height(10.dp))
        //LazyColumn用于垂直展示可滚动的列表。LazyRow用于横向滚动
        LazyColumn(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.White)
        ) {
        //items(items):将 items 列表中的每个 item 传递给 ItemView 组件。
            items(items) { item ->
                ItemView(item = item)
            }
        }
    }
}

【Column】

@Composable
inline fun Column(
    modifier: Modifier = Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    content: @Composable ColumnScope.() -> Unit
) {
    val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
    Layout(
        content = { ColumnScopeInstance.content() },
        measurePolicy = measurePolicy,
        modifier = modifier
    )
}

modifier: Modifier = Modifier: Modifier 是用于修饰和调整布局的参数,例如设置边距、填充、对齐等。默认值为 Modifier,即没有附加任何修饰符。

verticalArrangement: Arrangement.Vertical = Arrangement.Top: Arrangement.Vertical 定义了子项在垂直方向上的排列方式。Arrangement.Top 表示子项从容器顶部开始排列。其他值如 Arrangement.Center、Arrangement.Bottom 等可以调整排列方式。

horizontalAlignment: Alignment.Horizontal = Alignment.Start: Alignment.Horizontal 定义了子项在水平方向上的对齐方式。Alignment.Start 表示子项在容器的开始(左侧)对齐。其他值如 Alignment.CenterHorizontally、Alignment.End 等可以调整对齐方式。

content: @Composable ColumnScope.() -> Unit: 这是一个 lambda 函数类型的参数,代表了 Column 的子内容。ColumnScope 是一个特定的作用域,允许在 content 中使用 Column 相关的函数来添加子项。

【Button】

@Composable
fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    elevation: ButtonElevation? = ButtonDefaults.elevation(),
    shape: Shape = MaterialTheme.shapes.small,
    border: BorderStroke? = null,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
) {
    val contentColor by colors.contentColor(enabled)
    Surface(
        modifier = modifier,
        shape = shape,
        color = colors.backgroundColor(enabled).value,
        contentColor = contentColor.copy(alpha = 1f),
        border = border,
        elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
        onClick = onClick,
        enabled = enabled,
        role = Role.Button,
        interactionSource = interactionSource,
        indication = rememberRipple()
    ) {
        CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
            ProvideTextStyle(
                value = MaterialTheme.typography.button
            ) {
                Row(
                    Modifier
                        .defaultMinSize(
                            minWidth = ButtonDefaults.MinWidth,
                            minHeight = ButtonDefaults.MinHeight
                        )
                        .padding(contentPadding),
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically,
                    content = content
                )
            }
        }
    }
}


onClick: () -> Unit: 点击按钮时调用的回调函数。

modifier: Modifier = Modifier: 用于修饰按钮的 Modifier,可以设置尺寸、边距等。

enabled: Boolean = true: 按钮是否启用,默认为 true。

interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }: 用于处理按钮的交互状态。

elevation: ButtonElevation? = ButtonDefaults.elevation(): 按钮的阴影效果,默认为 ButtonDefaults.elevation(),即系统默认值。

shape: Shape = MaterialTheme.shapes.small: 按钮的形状,默认为 MaterialTheme 中定义的小形状。

border: BorderStroke? = null: 按钮的边框样式,默认为 null,即没有边框。

colors: ButtonColors = ButtonDefaults.buttonColors(): 按钮的颜色配置,默认为系统默认颜色。

contentPadding: PaddingValues = ButtonDefaults.ContentPadding: 按钮内容的内边距,默认为系统默认值。

content: @Composable RowScope.() -> Unit: 按钮的内容,使用 RowScope 作用域来定义其布局。

【Spacer】

@Composable
fun Spacer(modifier: Modifier) {
    Layout({}, modifier) { _, constraints ->
        with(constraints) {
            val width = if (hasFixedWidth) maxWidth else 0
            val height = if (hasFixedHeight) maxHeight else 0
            layout(width, height) {}
        }
    }
}

【LazyColumn】

@Composable
fun LazyColumn(
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    content: LazyListScope.() -> Unit
) {
    LazyList(
        stateOfItemsProvider = rememberStateOfItemsProvider(content),
        modifier = modifier,
        state = state,
        contentPadding = contentPadding,
        flingBehavior = flingBehavior,
        horizontalAlignment = horizontalAlignment,
        verticalArrangement = verticalArrangement,
        isVertical = true,
        reverseLayout = reverseLayout
    )
}

modifier: Modifier = Modifier:

modifier 用于设置 LazyColumn 的外观和布局特性,如宽度、高度、边距等。
state: LazyListState = rememberLazyListState():

state 管理列表的滚动状态,包括当前位置、可见项等。
rememberLazyListState() 是一个用于记住列表状态的函数。
contentPadding: PaddingValues = PaddingValues(0.dp):

contentPadding 设置列表内容的内边距。
默认值是 0.dp,表示没有内边距。
reverseLayout: Boolean = false:

reverseLayout 决定列表的滚动方向。
如果为 true,列表将从底部开始显示到顶部;否则,从顶部开始显示到底部。
verticalArrangement: Arrangement.Vertical:

verticalArrangement 定义了垂直方向上子项的排列方式。
根据 reverseLayout 的值,设置为 Arrangement.Top 或 Arrangement.Bottom。
horizontalAlignment: Alignment.Horizontal = Alignment.Start:

horizontalAlignment 设置列表项在水平方向上的对齐方式。
默认是 Alignment.Start,即左对齐。
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior():

flingBehavior 决定列表滚动的惯性行为。
默认使用 ScrollableDefaults.flingBehavior(),这是一个标准的惯性滚动行为。
content: LazyListScope.() -> Unit:

content 是一个 lambda 表达式,用于定义列表中的项。
在 LazyListScope 中,你可以使用 items 或 item 等函数来添加列表项。

我们发现,怎么每个函数都带一个【Modifier】?

【Modifier】 是 Jetpack Compose 中的一个核心概念,用于修改和定制组件的布局、外观和行为。每个 Compose 组件都可以接收一个 Modifier 参数来进行这些调整。

以下是一些常用的 Modifier 属性及其使用方法:

padding:
作用: 设置组件的内边距。
用法: Modifier.padding(all = 16.dp)Modifier.padding(start = 8.dp, end = 8.dp)


background:
作用: 设置组件的背景颜色或背景图像。
用法: Modifier.background(Color.Gray)Modifier.background(brush = Brush.linearGradient(listOf(Color.Red, Color.Blue)))


fillMaxWidth:
作用: 使组件宽度填充父容器的最大宽度。
用法: Modifier.fillMaxWidth()


fillMaxHeight:
作用: 使组件高度填充父容器的最大高度。
用法: Modifier.fillMaxHeight()


width 和 height:
作用: 设置组件的宽度和高度。
用法: Modifier.width(100.dp)Modifier.height(200.dp)


size:
作用: 同时设置组件的宽度和高度。
用法: Modifier.size(100.dp)


align:
作用: 设置组件在父容器中的对齐方式。
用法: Modifier.align(Alignment.Center)


border:
作用: 为组件添加边框。
用法: Modifier.border(2.dp, Color.Black)


clickable:
作用: 设置组件可以点击,并指定点击事件。
用法: Modifier.clickable { /* Handle click */ }


graphicsLayer:
作用: 应用图形变换,如缩放、旋转、透明度等。
用法: Modifier.graphicsLayer(scaleX = 1.5f, scaleY = 1.5f)

通过组合和链式调用不同的 Modifier,可以很方便地实现复杂的 UI 布局和样式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2141108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java,深拷贝和浅拷贝

在 Java 中&#xff0c;深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是对象拷贝的两种方式&#xff0c;主要区别在于它们如何处理对象的内部引用。 目录 一、浅拷贝&#xff08;Shallow Copy&#xff09; 实现方式 二、深拷贝&…

国际商城系统怎么弄 跨境电商商城怎样上线

国际商城系统一般涉及多个关键步骤。首先&#xff0c;需要选择合适的平台或开发工具&#xff0c;如商淘云国际电商系统或自定义开发。其次&#xff0c;系统应支持多语言、多币种以及国际支付网关&#xff0c;以满足全球客户的需求。第三&#xff0c;确保系统具有强大的物流和配…

推荐5款AI论文大纲生成器,一键极速生成!

在当今学术研究和写作领域&#xff0c;AI论文大纲生成器的出现极大地提高了写作效率和质量。以下是五款功能强大且全面的AI论文大纲生成器推荐&#xff1a; 一、千笔-AIPassPaper 千笔-AIPassPaper是一款基于深度学习和自然语言处理技术的AI写作助手&#xff0c;旨在帮助用户…

新160个crackme - 058-CZG-crackme1

运行分析 按下OK键后&#xff0c;程序退出 PE分析 C程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida函数栏发现winMain(x,x,x,x)&#xff0c;即打开窗口&#xff0c;双击函数跟进 继续跟进 双击DialogFunc函数&#xff0c;这个是窗口逻辑 继续跟进sub_401090函…

数据结构----栈和队列

&#xff08;一&#xff09;栈 1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First …

GFS 分布式文件系统 GlusterFS

一、GlusterFS概述 1.1、GlusterFS简介 GlusterFS 是一个开源的分布式文件系统。由存储服务器、客户端以及NFS/Samba 存储网关&#xff08;可选&#xff0c;根据需要选择使用&#xff09;组成。 包括其去中心化&#xff08;无元数据服务器&#xff09;的特性&#xff0c;这有…

【苍穹外卖】总结

1 pom 依赖 1.1 MyBatis Spring 用于简化 MyBatis 与 Spring Boot 的集成&#xff0c;提供了对 MyBatis 框架的自动配置支持&#xff0c;简化了数据访问层的开发 1.2 Lombok Lombok 是一个 Java 库&#xff0c;能够通过注解自动生成常见的代码&#xff08;如 getter、setter、…

双亲委派机制知识点

类加载器 双亲委派模型 为什么采用双亲委派模型 打破双亲委派机制的场景 Tomcat 打破双亲委派机制:目的是可以加载不同版本的jar包 实现类隔离&#xff1a;在Tomcat中&#xff0c;每个Web应用使用独立的类加载器加载类文件&#xff0c;这样做的好处在于&#xff0c;当在同一T…

C++二叉搜索树(二叉树进阶)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 C二叉搜索树(二叉树进阶) 收录于专栏 [C进阶学习] 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 二叉搜索树…

Java重修笔记 第五十七天 坦克大战(七)多线程基础 - 编程练习

1. 线程之间的协调控制&#xff08;通知方式&#xff09; public class Homework04 {public static void main(String[] args) {// 在 main 方法中启动两个线程// 第一个线程内循环打印 1 到 100 以内的整数// 直到第二个线程从键盘读取到 "Q" 指令后结束第一个线程…

Porcupine - 语音关键词唤醒引擎

文章目录 一、关于 Porcupine特点用例尝试一下 语言支持性能 二、Demo1、Python Demo2、iOS DemoBackgroundService DemoForegroundApp Demo 3、网页 Demo3.1 Vanilla JavaScript 和 HTML3.2 Vue Demos 三、SDK - Python 一、关于 Porcupine Porcupine 是一个高度准确和轻量级…

LC并联电路在正弦稳态下的传递函数推导(LC并联谐振选频电路)

LC并联电路在正弦稳态下的传递函数推导&#xff08;LC并联谐振选频电路&#xff09; 本文通过 1.解微分方程、2.阻抗模型两种方法推导 LC 并联选频电路在正弦稳态条件下的传递函数&#xff0c;并通过仿真验证不同频率时 vo(t) 与 vi(t) 的幅值相角的关系。 电路介绍 已知条件…

Axure RP实战:打造高效图形旋转验证码

Axure RP实战&#xff1a;打造高效图形旋转验证码 在数字产品设计的海洋中&#xff0c;验证码环节往往是用户交互体验的细微之处&#xff0c;却承载着验证用户身份的重要任务。 传统的文本验证码虽然简单直接&#xff0c;但随着用户需求的提高和设计趋势的发展&#xff0c;它…

vue2的diff算法

Vue2 的虚拟 DOM diff 算法是一种高效的算法&#xff0c;用于比较新旧两个虚拟 DOM 树&#xff0c;找出差异并更新到真实 DOM 上。这个算法的核心在于尽量减少不必要的 DOM 操作&#xff0c;提高性能。 虚拟dom&#xff1a;把DOM数据化&#xff0c;先通过不断地操作数据&#…

如何在手机端跑大模型?

最近新入手了一台 arm 开发板&#xff0c;内置安装了 Android 13 系统。 昨天把网络问题给解决了&#xff1a;安卓连接 WIFI 但无法上网&#xff1f;盘点踩过的那些坑 今日分享&#xff0c;继续带大家实操&#xff1a;如何把大模型&#xff08;LLM&#xff09;部署到移动端&a…

文章资讯职场话题网站源码整站资源自带2000+数据

介绍&#xff1a; 数据有点多&#xff0c;数据资源包比较大&#xff0c;压缩后还有250m左右。值钱的是数据&#xff0c;网站上传后直接可用&#xff0c;爽飞了 环境&#xff1a;NGINX1.18 mysql5.6 php7.2 代码下载

JUC学习笔记(三)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 八、共享模型之工具--JUC8.1 AQS 原理1. 概述2 实现不可重入锁自定义同步器自定义锁 3.心得起源目标设计1) state 设计2&#xff09;阻塞恢复设计3&#xff09;队列…

学习笔记 韩顺平 零基础30天学会Java(2024.9.16)

P563 自定义泛型方法 当调用方法时&#xff0c;要传入参数&#xff0c;因为当传入参数时&#xff0c;编译器就可以确定泛型代表的类型 泛型方法和方法使用了泛型是不一样的 泛型方法可以使用类声明的泛型&#xff0c;也可以使用自己的泛型 P564 泛型方法练习 P565 泛型的继承和…

Python编码系列—Python适配器模式:无缝集成的桥梁

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

二叉树OJ题——另一棵树的子树

文章目录 一、题目链接二、解题思路三、解题代码 一、题目链接 另一棵树的子树 题目描述&#xff1a;判断当前树A是否是树B的子树。 二、解题思路 时间复杂度&#xff1a;O(n*m) 三、解题代码