Compose -- Button

322 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

概述

上一篇学习笔记中学习了AppBar的简单使用,AppBar向我们提供一个通用的标题栏可组合项,使用AppBar能够快速创建出一个满足设计要求的顶部或者底部标题栏。这篇笔记将会学习在开发中使用非常多的一个可组合项--按钮,按钮在App几乎无所不在,算是和用户交互最多的一个可组合项了,下面将会学习按钮的简单使用。

Button

Button的使用非常简单,直接定义Button可组合项即可,普通的Button可组合项和View体系中的Button是不一样的,View体系中的Button更多的是对TextView的包装。而Button可组合项更多的是关心自身的状态,也就是说Button可组合项是一个可以按下的按钮,至于这个按钮是什么样的,由其中的子可组合项指定。

下面的代码演示了定义了一个简单的按钮,其中没有任何子可组合项:

    Button(onClick = { controller.popBackStack() }) {}

这样就定义了一个按钮,当我们点击这个按钮的时候就会退出当前的可组合项,返回到上一个目的地。这个按钮显示的效果如下:

定义一个简单的按钮

可以看到,这个按钮是有默认的属性的,这里因为我们使用的其实是material包中定义的按钮,这个包下的可组合项本身就是带有默认属性的,用于让我们快速实现满足材料设计的应用。

设置子可组合项

普通的按钮只是为我们实现了可以点击的效果以及点击之后的回调,大多数时候我们都需要向其中提供一个子可组合项来向用户说明当前按钮的作用,一般情况下我们使用的是一个为本,如下面的代码所示:

            Button(
                onClick = { },
            ) {
                Text(text = "返回",color = Color.White)
            }

上面的代码就实现了带有文字的按钮,运行后可以看到效果如下:

带有文字的按钮

如果查看Button的源码定义的话,我们回发现其content参数可以接收的数据类型为:content: @Composable RowScope.() -> Unit,这是一个横向排列子项的布局,其实就是Row,基于这个特性,Button可以接收多个子项,并按照水平顺序排列这些子项,如下面的代码所示:

带有图标的按钮

上面的代码就实现了一个带有图标的按钮,既然是RowScope的扩展函数,那么就可以使用它的特性去调整子项的布局,如下面的代码所示:

            Button(onClick = { }) {
                Icon(
                    painterResource(id = R.drawable.ic_menu_white_24),
                    "菜单",
                    tint = Color.White
                )
                Text(text = "点击菜单", modifier = Modifier.weight(1f), textAlign = TextAlign.Center)
            }

可以看到,我们可以使用weight属性调整子可组合项的位置。

设置尺寸

使用modifier属性就可以设置按钮的尺寸信息,但是有时候我们可能需要设置按钮距离父项或者其它可组合项的尺寸,类似于我们需要实现margin的效果,这种时候我们其实可以通过modifier.padding()去实现,虽然是padding,但是最终的效果就是类似于margin的效果,如下的代码所示:

            //设置尺寸
            Button(
                onClick = { },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 10.dp, vertical = 5.dp)
            ) {
                Text(text = "设置寸尺")
            }

运行上面的代码,可以看到如下的效果:

设置按钮的尺寸

按钮同时向我们提供了contentPadding属性,但是和modifier.padding不同的地方在于:contentPadding设置的是按钮内部真实的padding,可以认为,modifier.padding()设置的就是margin,而contentPadding设置的才是内边距,如下面的代码所示:

            Button(
                onClick = {},
                modifier = Modifier
                    .fillMaxWidth(),
                contentPadding = PaddingValues(20.dp)
            ) {
                Text(text = "设置寸尺")
            }

运行上面的代码可以看到如下的效果:

设置按钮的内边距

设置颜色

虽然按钮是带有默认的颜色的,但是很多时候并不能满足我们的需求,如果我们需要给按钮指定颜色,那么可以使用colors属性,这个属性并不是设置一个颜色,而是指定一系列的颜色,包括背景颜色,内容填充颜色,不可用时候的背景颜色,不可用时候的内容填充颜色,如下面的代码所示:

            val colorButtonEnableState = remember {
                mutableStateOf(true)
            }
            //设置按钮的颜色
            Button(
                onClick = { colorButtonEnableState.value = !colorButtonEnableState.value },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 10.dp, end = 10.dp, bottom = 10.dp),
                colors = ButtonDefaults.buttonColors(
                    backgroundColor = Color.LightGray,
                    contentColor = Color.Magenta,
                    disabledBackgroundColor = Color.DarkGray,
                    disabledContentColor = Color.White
                ),
                enabled = colorButtonEnableState.value
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_search_white_24),
                    contentDescription = "搜索"
                )
                Text(text = "搜索")
            }

在上面的代码中我们分别指定了按钮在不同状态下的颜色,我们可以通过设置按钮提供的enable的参数来设置按钮是否可用,在上面的代码中点击按钮之后将会由一开始的可用状态变成不可用的状态,按钮的背景颜色和填充颜色也会随之改变,运行上面的代码可以看到如下的效果:

设置按钮的颜色

设置形状

除了颜色,很多时候我们还需要自定义按钮的形状和边框,通过shapeborder这两个属性可以定义形状和边框,如下代码所示:

            Button(
                onClick = { /*TODO*/ },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 10.dp, end = 10.dp, bottom = 10.dp, top = 20.dp),
                shape = RoundedCornerShape(20.dp),
                contentPadding = PaddingValues(vertical = 5.dp),
                border = BorderStroke(
                    5.dp, Brush.linearGradient(listOf(Color.Cyan, Color.Magenta))
                )
            ) {
                Text(text = "设置按钮的形状")
            }

在上面的代码中,我们就设置了按钮的形状为圆角矩形,其中圆角的大小为20dp,同时通过border属性指定了边框线条,线条的宽度为5dp,同时设置了线条使用的是渐变颜色,这里渐变颜色使用的是线性渐变,运行上面的程序,可以看到如下的效果:

设置按钮的形状

OutlinedButton

这是材料设计中用于辅助强调的按钮,并不是主强调按钮,因此这个按钮的默认实现是没有Z轴高度的,如果需要有Z轴高度的按钮,则应该使用Button,下面的代码实现了一个默认的OitlinedButton:

            OutlinedButton(
                onClick = { /*TODO*/ },
                Modifier
                    .fillMaxWidth()
                    .padding(10.dp)
            ) {
                Text(text = "这是一个OutlinedButton")
            }

运行上面的程序可以看到如下的效果:

OutlinedButton

虽然这里的默认效果不支持显示Z轴的高度,但是我们仍然可以通过elevation属性指定它的Z轴高度,指定之后也是能够显示出来的。除了默认效果不同,OttlinedButton其它使用方法和Button的使用是一样的。

TextButton

这是材料设计中帮我们声明的一个文本按钮,文本按钮和普通的Button比较没有设置背景颜色和Z轴的高度,也没有像OutlinedButton的边框线条,看起来和一个普通的Text没有什么区别,但是在点击之后仍然能看到水波纹效果,下面的代码演示了一个TextButton的使用:

            TextButton(
                onClick = { /*TODO*/ },
                Modifier
                    .fillMaxWidth()
                    .padding(10.dp)
            ) {
                Text(text = "这是一个TextButton")
            }

运行上面的代码可以看到如下的效果:

TextButton

TextButton也可以使用Button中相应的属性来达到设计的效果,但是其仍然主要用于在类似卡片中提供的一个按钮操作。

至此,Button简单的使用就学习完了。可以看到,Button的使用还是比较简单的,得益于Compose可组合项的思想,按钮可以实现非常多的效果,我们不必再局限于View体系中Button提供的少量属性,使用可组合项能够让一个按钮出现各种各样的可能。