Android Jetpack Compose介绍

一、背景介绍

Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发。

2019年5月,Google在I/O大会上公布Compose
2020年9月,发布第一个Alpha版本
2021年7月,发布第一个稳定版本

1.1 主要内容

二、预备知识

2.1 默认参数

参数指定默认值。

/**
 * 默认参数
 */
class DefaultParam {
    companion object {
        private const val TAG = "DefaultParam"
    }

    // 默认参数
    fun test1(a: Int, b: String = "") {
        Log.e(TAG, "test1: a:$a b:$b")
    }

    // 默认参数数据类
    data class Test(val a: Int = 0, val b: Int)

    fun test() {
        // 方法最后参数提供了默认值,签名参数不需要指定形参名称 b,直接传值
        test1(0)

        // 命名参数可以忽略传参顺序
        test1(
            b = "test",
            a = 2
        )

        // 构造方法第一个参数提供了默认值,第二个参数还是需要指定形参名称 b
        Test(b = 2)
    }

    // 解构数据类,得到 a 和 b
    fun testData() {
        val test = Test(b = 2)
        val (a, b) = test
        Log.e(TAG, "a=$a")
        Log.e(TAG, "b=$b")
    }
}

函数参数很多时,可以分为必选参数和可选参数。命名参数可以不按照顺序传参。

举例:
文本控件只需要传入文字是什么。
Text API定义

@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
){...}

2.2 高阶函数

参数是函数的函数。

/**
 * 高阶函数
 */
class HigherFunction {
    companion object {
        private const val TAG = "HigherFunction"
    }

    fun high(one: (String) -> Unit, string: String) {
        one(string)
//            one.invoke(string)
    }

    fun high2(two: () -> Unit) {
        two()
    }

    fun test() {
        high({
            Log.e(TAG, "test: string: $it")
        }, "test")
    }

    fun test2() {
        // 尾随lambda:函数的最后一个参数是函数类型(lambda)时,可以把 {} 写在函数外部。
        // 如果除lambda之外没有其他参数,可以省略圆括号
        high2 {
            Log.e(TAG, "test2: string")
        }
    }
}

举例:
Column布局,最后一个参数 content 是函数类型。

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

使用 Column

Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            // 3 ImageView
            Image(
                modifier = Modifier
                    .size(LOGO_HEIGHT)
                    .alpha(alpha = alphaState),
                painter = painterResource(id = getLogo()),
                contentDescription = stringResource(id = R.string.compose)
            )
            // 4 TextView
            Text(
                text = stringResource(id = R.string.compose),
                color = MaterialTheme.colors.splashText,
                style = MaterialTheme.typography.h5,
                fontWeight = FontWeight.Bold,
                maxLines = 1
            )
        }

三、第一个Compose程序

3.1 HelloWorld

class ComposeMainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Greeting(name = "Compose")
        }
    }

    @Composable
    fun Greeting(name: String) {
        Text(
          text = "Hello $name"
        )
    }

}

3.2 预览

使用 @Preview 预览,可以同时存在多个预览 。

    @Preview(showBackground = true)
    @Composable
    fun GreetingPreview() {
        Greeting(name = "World")
    }

    @Preview(showBackground = true)
    @Composable
    fun GreetingPreview2() {
        Greeting(name = "Compose")
    }

在这里插入图片描述

交互式预览

    @Composable
    fun Counter(count: Int, updateCount: (Int) -> Unit) {
        Button(
            onClick = { updateCount(count + 1) },
            colors = ButtonDefaults.buttonColors(
                backgroundColor = if (count > 5) Color.Green else Color.White
            )
        ) {
            Text("I've been clicked $count times")
        }
    }

    @Preview
    @Composable
    fun PreviewCounter() {
        // mutableStateOf 使 counterState 的值能被 Compose 观察到
        // remember 记住 counterState 当前值
        val counterState = remember { mutableStateOf(0) }

        Counter(
            count = counterState.value,
            updateCount = { newCount ->
                counterState.value = newCount
            }
        )
    }

点击1次

在这里插入图片描述

点击6次

在这里插入图片描述

四、简单控件

4.1 文本

    Text(
        text = stringResource(id = R.string.compose),
        color = MaterialTheme.colors.splashText,
        style = MaterialTheme.typography.h5,
        fontWeight = FontWeight.Bold,
        maxLines = 1
    )

在这里插入图片描述

4.2 输入框

    val text = remember { mutableStateOf("你好") }
    TextField(
        value = text.value,
        onValueChange = { text.value = it },
        label = { Text("标签") }
    )

在这里插入图片描述

4.3 按钮

    val i = remember {
        mutableStateOf(0)
    }
    Button(onClick = {
        i.value++
    }) {
        Text(
            text = "按钮 ${i.value}"
        )
    }

在这里插入图片描述

4.4 图片

    Image(
        modifier = Modifier
            .size(LOGO_HEIGHT),
        painter = painterResource(id = getLogo()),
        contentDescription = stringResource(id = R.string.compose)
    )

在这里插入图片描述

4.5 进度条

// 圆形进度条
CircularProgressIndicator()

在这里插入图片描述

五、布局

5.1 线性布局

Column 纵向线性布局

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text("One")
        Text("Two")
        Text("Three")
    }

在这里插入图片描述

Row 横向线性布局

    Row(
        modifier = Modifier.fillMaxSize(),
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text("One")
        Text("Two")
        Text("Three")
    }

在这里插入图片描述

5.2 盒布局

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Row {
            Box(
                contentAlignment = Alignment.TopStart,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Gray),
            ) {
                Text("1", fontSize = 20.sp)
            }

            Box(
                contentAlignment = Alignment.TopCenter,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Magenta),
            ) {
                Text("2", fontSize = 20.sp)
            }
            Box(
                contentAlignment = Alignment.TopEnd,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Cyan),
            ) {
                Text("3", fontSize = 20.sp)
            }
        }
        Row {
            Box(
                contentAlignment = Alignment.CenterStart,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.DarkGray),
            ) { Text("4", fontSize = 20.sp) }

            Box(
                contentAlignment = Alignment.Center,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Green),
            ) {
                Text("5", fontSize = 20.sp)
            }
            Box(
                contentAlignment = Alignment.CenterEnd,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Red)
            ) {
                Text(
                    "6",
                    fontSize = 20.sp
                )
            }
        }

        Row {
            Box(
                contentAlignment = Alignment.BottomStart,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Magenta),
            ) { Text("7", fontSize = 20.sp) }
            Box(
                contentAlignment =
                Alignment.BottomCenter,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Yellow),
            ) {
                Text(
                    "8",
                    fontSize = 20.sp
                )
            }
            Box(
                contentAlignment = Alignment.BottomEnd,
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Magenta),
            ) {
                Text("9", fontSize = 20.sp)
            }
        }
    }

每一行是 3 个 Box,使用 contentAlignment 控制内容文本的对齐方式。

在这里插入图片描述

5.3 约束布局

ConstraintLayout

@Preview(showBackground = true)
@Composable
fun Preview() {
    ConstraintLayout(modifier = Modifier.fillMaxSize()) {
        val (one, two) = createRefs()
        val three = createRef()
        DefaultText(
            "One",
            modifier = Modifier.constrainAs(one) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
                top.linkTo(parent.top, margin = 16.dp)
            })
        DefaultText(
            "Two",
            Modifier.constrainAs(two) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
                top.linkTo(one.bottom, margin = 16.dp)

            })
        DefaultText(
            "Three",
            Modifier.constrainAs(three) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
                bottom.linkTo(parent.bottom, margin = 16.dp)
            })
    }
}


@Composable
fun DefaultText(text: String, modifier: Modifier) {
    Text(
        text,
        modifier = modifier
            .size(100.dp)
            .background(Color.Red),
        fontSize = 30.sp,
        textAlign = TextAlign.Center
    )
}

在这里插入图片描述

5.4 修饰符

Modifier
内边距 padding

@Preview(showBackground = true)
@Composable
fun Preview() {
    Text("Zhujiang", modifier = Modifier.padding(50.dp))
}

@Preview(showBackground = true)
@Composable
fun Preview2() {
    Text("Zhujiang2", modifier = Modifier.padding(0.dp))
}

在这里插入图片描述

控件尺寸

@Preview(showBackground = true)
@Composable
fun Preview() {
    Text("Zhujiang", modifier = Modifier.fillMaxSize())
}

@Preview(showBackground = true)
@Composable
fun Preview2() {
    Text("Zhujiang", modifier = Modifier.fillMaxWidth())
}

在这里插入图片描述

当什么都不设置的时候,就是自适应大小。

@Preview(showBackground = true)
@Composable
fun Preview() {
    Text("Zhujiang", modifier = Modifier.size(width = 100.dp, height = 110.dp))
}

@Preview(showBackground = true)
@Composable
fun Preview2() {
    Text("Zhujiang")
}

在这里插入图片描述

weight 权重


@Preview(showBackground = true)
@Composable
fun Preview() {
    Row(
        Modifier
            .fillMaxSize()
            .padding(top = 10.dp)
    ) {
        Box(
            Modifier
                .weight(2f)
                .height(50.dp)
                .background(Color.Blue)
        )
        Box(
            Modifier
                .weight(1f)
                .height(50.dp)
                .background(Color.Red)
        )
    }
}

在这里插入图片描述

点击事件


@Preview(showBackground = true)
@Composable
fun Preview() {
    val context = LocalContext.current

    Text(
        "Click",
        modifier = Modifier
            .background(Color.Green)
            .clickable {
                // 执行点击事件需要的操作
                Toast
                    .makeText(context, "click it", Toast.LENGTH_SHORT)
                    .show()
            },
        fontSize = 30.sp,
        textAlign = TextAlign.Center
    )
}

在这里插入图片描述

5.5 脚手架

Scaffold 脚手架,它实现了基本的 MaterialDesign 可视化的布局结构,提供了用于显示 drawer(侧边抽屉)、topbar、snackbar 和底部导航栏的 API。

@Preview(showBackground = true)
@Composable
fun Preview() {
    Scaffold(
        topBar = {
            /*.标题栏..*/
            TopAppBar(
                title = { Text("标题") },
                navigationIcon = {
                    IconButton(onClick = {  /*.点击事件..*/ })
                    {
                        Icon(Icons.Filled.ArrowBack, "")
                    }
                })
        },
        floatingActionButton = { /*.悬浮按钮..*/
            FloatingActionButton(onClick = {            // Floating点击事件
            }) {
                Text("OK")
            }
        },
        content = { /*.主内容..*/
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Text("主屏幕", fontSize = 40.sp)
            }
        }
    )
}

在这里插入图片描述

六、复杂控件

6.1 列表

纵向列表 LazyColumn


@Preview(showBackground = true, widthDp = 200, heightDp = 400)
@Composable
fun Preview() {
    // 准备数据
    val dataList = arrayListOf<Int>()
    for (index in 0..10) {
        dataList.add(index)
    }

    LazyColumn {
        items(dataList) { data ->
            // item布局
            Text("item:$data")
        }
    }
}

在这里插入图片描述

多类型

@Preview(showBackground = true, widthDp = 200, heightDp = 400)
@Composable
fun Preview() {
    // 准备数据
    val charList = arrayListOf<Chat>().apply {
        add(Chat("你好啊"))
        add(Chat("你在干啥呢"))
        add(Chat("想问你个事"))
        add(Chat("没干啥,还在写代码啊!", false))
        add(Chat("啥事啊大哥?", false))
        add(Chat("没事。。。"))
        add(Chat("好吧。。。", false))
    }

    LazyColumn {
        items(charList) { data ->
            // 1. 左边消息样式
            if (data.isLeft) {
                Column(modifier = Modifier.padding(end = 20.dp)) {
                    Spacer(modifier = Modifier.height(5.dp))
                    Text(
                        data.content, modifier = Modifier
                            .fillMaxWidth()
                            .height(25.dp)
                            .background(Color.Magenta)
                    )
                }
            } else {
                // 2. 右边消息样式
                Column(modifier = Modifier.padding(start = 20.dp)) {
                    Spacer(modifier = Modifier.height(5.dp))
                    Text(
                        data.content, modifier = Modifier
                            .fillMaxWidth()
                            .background(Color.Green)
                            .height(25.dp)
                    )
                }
            }
        }
    }
}

在这里插入图片描述

6.2 网格

LazyVerticalGrid

@ExperimentalFoundationApi
@Preview(showBackground = true, widthDp = 200, heightDp = 400)
@Composable
fun Preview() {
    // 准备数据
    val photos = arrayListOf<Int>()
    for (index in 0..20) {
        photos.add(R.drawable.ic_launcher_background)
    }

    LazyVerticalGrid(
        // 自适应宽度
        cells = GridCells.Adaptive(minSize = 60.dp)
    ) {
        items(photos) { photo ->
            Image(
                painter = painterResource(
                    photo
                ),
                "",
                modifier = Modifier.padding(2.dp)
            )
        }
    }
}

在这里插入图片描述

6.3 底部导航栏

BottomNavigation


enum class Tabs(
    val title: String, @DrawableRes val icon: Int
) {
    ONE("One", R.drawable.ic_nav_news_normal),
    TWO("Two", R.drawable.ic_nav_tweet_normal),
    THREE("Three", R.drawable.ic_nav_discover_normal),
    FOUR("Fore", R.drawable.ic_nav_my_normal)
}

@Composable
fun One() {
    BaseDefault("One")
}

@Composable
fun Two() {
    BaseDefault("Two")
}

@Composable
fun Three() {
    BaseDefault("Three")
}

@Composable
fun Four() {
    BaseDefault("Four")
}

@Composable
fun BaseDefault(content: String) {
    Row(
        modifier = Modifier.fillMaxSize(),
        horizontalArrangement =
        Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically,
    ) { Text(content, fontSize = 50.sp) }
}

@ExperimentalFoundationApi
@Preview(showBackground = true, widthDp = 200, heightDp = 400)
@Composable
fun Preview() {
    // Tab数据
    val tabs = Tabs.values()
    // 使用remember记住State值
    var position by remember { mutableStateOf(Tabs.ONE) }
    // 脚手架,方便实现页面
    Scaffold(
        backgroundColor = Color.Yellow,
        // 定义bottomBar
        bottomBar = {
            BottomNavigation {
                tabs.forEach { tab ->
                    BottomNavigationItem(
                        modifier = Modifier.background(MaterialTheme.colors.primary),
                        icon = { Icon(painterResource(tab.icon), contentDescription = null) },
                        label = { Text(tab.title) },
                        selected = tab == position,
                        onClick = { position = tab },
                        alwaysShowLabel = false,
                    )
                }
            }
        }) {
        // 根据State值的变化来动态切换当前显示的页面
        when (position) {
            Tabs.ONE -> One()
            Tabs.TWO -> Two()
            Tabs.THREE -> Three()
            Tabs.FOUR -> Four()
        }
    }
}

在这里插入图片描述

七、相关资料

Jetpack Compose:Android全新UI编程
Jetpack Compose 教程

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值