带你用Jetpack Compose 创建第一个UI

1,519 阅读4分钟

How to create realistic UI with Jetpack Compose(Part II)
作者:Kruti Kamani

FlowerApp

我们已经在之前的文章Saying Hello to Jetpack Compose介绍过Jetpack Compose的基础概念了。

Jetpack Compose是是一种用声明式的构建Android应用UI的新方式。现在不需要任何xml你也可以写一个Android APP了。

构建UI真的可以不需要XML了吗?

是的!用最新的Jetpack Compose这个现代化的UI工具你就可以做到。通过Compose只需要要定义一套Composable的函数就可以构建UI了,这套Composable函数接收数据然后将UI元素给展示出来。

Jetpack Compose这套声明式UI设计模式的几个关键点:

  • 提高开发效率:跟现有的代码完全兼容。
  • 更少的代码:用更少的代码反而可以做更多的事情,同时避免整个类的问题,因此代码更简洁,也更容易维护。
  • 更强大的工具:利用Android平台提供的API,可以创建更具吸引力的APP。
  • 直观思维:你只需要把UI描述出来,然后剩下的就可以交给Compose了。每次状态改变,UI会自动更新。

这边文章,我们会创一个一个来自Dribbble shotsFlower app的UI,并学习怎么用Jetpack Compose构建简单的UI。不浪费大家时间,直接开始吧。

快速开始

开始之前Jetpack Compose 之前需要配置一组gradle依赖。

//App level build.gradle
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.ui:ui-tooling:$compose_version" 

还有compose的标记需要置为true,这个在android下面的buildFeatures块里面。

//App level build.gradle
buildFeatures {
    compose true
}

Compose APP的入口

因为Jetpack Compose以编程的方式去构建UI,所以你不再需要任何XML了。因此你也不在需要去调用setContentView(R.layout.activity_main), 而是需要去构建setContent这个方法。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Text("Hello, World!")
        }
    }
}

让我们创建一个flower的列表,展示一些基本信息

如果我们需要设计的UI不止这些元素的话,那我们可能还需要线性布局,相对布局或者是约束布局,来实现更完美的设计。

在Jetpack里面为了达到相同的效果,我们需要用到一些特殊的容器,比如Column就是其中之一。

Column { 
    //Write your design here
}

正如这个函数名描述的那样,这个函数会纵向的布局它的子元素。这里我们有一个纵向布局两个Text组件的例子。

@Composable
fun FlowerCard(flower: Flowers){
    Column {
        Text(
            text = flower.name,
            style = TextStyle(
                color = gray,
                fontSize = 16.sp
            )
        )
        Text(
            text = flower.price,
            style = TextStyle(
                color = colorPrimary,
                fontSize = 16.sp
            )
        )
    }

现在我们在flower信息的添加一个加号按钮。

正如你期望的那样,你可以用Row()函数来进行横向的布局子元素。默认的配置是所有的子元素紧挨着进行布局,没有空隙。

@Composable
fun FlowerCard(flower: Flowers){
    Row(modifier = Modifier.padding(20.dp)) {
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = flower.name,
                style = TextStyle(
                    color = gray,
                    fontSize = 16.sp
                )
            )
            Text(
                text = flower.price,
                style = TextStyle(
                    color = colorPrimary,
                    fontSize = 16.sp
                )
            )
        }
        IconButton(
            onClick = { },
            modifier = Modifier.background(
                color = colorPrimary,
                shape = RoundedCornerShape(10.dp)
            )
        ) {
            Icon(Icons.Default.Add, tint = Color.White)
        }
    }
}

上面的代码里面,我们通过Modifier添加了间距。但是modifier具体是什么东西呢?modifier是一个有序的,不可变的元素的集合,用来装饰或者给Compose UI元素添加行为的,比如背景,间距,点击事件等等。

现在我们再在row的基础上包一层Card。

@Composable
private fun FlowerCard(flower: Flowers) {
    Card(
        shape = RoundedCornerShape(14.dp),
        backgroundColor = Color.White,
        modifier = Modifier.padding(10.dp).width(180.dp)
    ) {
        Row(modifier = Modifier.padding(20.dp)) {
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = flower.name,
                    style = TextStyle(
                        color = gray,
                        fontSize = 16.sp
                    )
                )
                Text(
                    text = flower.price,
                    style = TextStyle(
                        color = colorPrimary,
                        fontSize = 16.sp
                    )
                )
            }
            IconButton(
                onClick = { },
                modifier = Modifier.background(
                    color = colorPrimary,
                    shape = RoundedCornerShape(10.dp)
                )
            ) {
                Icon(Icons.Default.Add, tint = Color.White)
            }
        }
    }
}

Card有非常丰富的属性。如果你想要一个圆形或者其他形状,通过modifier你可以给卡片添加间距,宽度和高度。Card可以一个子元素展示信息。

现在我们想添加花的图片到花的信息上面。也就是说,我们想在卡片上展示多个信息,但是我们知道Card只能接受一个子元素。因此我们必须用Column。

@Composable
private fun FlowerCard(flower: Flowers) {
    Card(
        shape = RoundedCornerShape(14.dp),
        backgroundColor = Color.White,
        modifier = Modifier.padding(10.dp).width(180.dp)
    ) {
        Column(
            modifier = Modifier.fillMaxWidth().padding(10.dp),
        ) {
            Image(
                modifier = Modifier.size(140.dp),
                asset = imageResource(id = flower.image)
            )
            Row(modifier = Modifier.padding(top = 20.dp)) {
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = flower.name,
                        style = TextStyle(
                            color = gray,
                            fontSize = 16.sp
                        )
                    )
                    Text(
                        text = flower.price,
                        style = TextStyle(
                            color = colorPrimary,
                            fontSize = 16.sp
                        )
                    )
                }
                IconButton(
                    onClick = { },
                    modifier = Modifier.background(
                        color = colorPrimary,
                        shape = RoundedCornerShape(10.dp)
                    )
                ) {
                    Icon(Icons.Default.Add, tint = Color.White)
                }
            }
        }
}

在上面的代码里面,为了添加一张图片我们用到了Image。

asset这个属性用来提供图片资源。imageResource函数接收一个一个图片的ID作为参数,然后将ImageAsset展示到View上面。Image还有很多其他属性,比如scaling,aligning,改变图片UI的展示等等。

创建一个花列表

通常创建一个列表你会用到RecyclerView。与之类似,在Jetpack Compose里面我们用LazyRowFor。这是一个横向的列表,只布局当前显示的item。

现在把所有的放在一起,创建PopularFlowersList()。

@Composable
private fun PopularFlowersList() {
    LazyRowFor(
        items = FlowersData.list,
        modifier = Modifier.fillMaxWidth()
    ) { flowers ->
        FlowerCard(flowers)
    }
}

恭喜你,你已经成功用Jetpack Compose成功创建了第一个真实的UI。

注意:因为Jetpack Compose目前还处于alpha(目前已经是beta),组件回这它们的属性都有可能改变。

这里贴一下例子的github链接

这篇文章只是这个系列的开始,在后续的文章里,我们计划用MVVM的设计模式写一个示例。所以请继续保持关注,到时候我们继续Composing!!