1. 前言
上篇文章 我们实现了 Compose Bloom项目的开发页,这篇文章接着上文,来介绍主页的开发。

2. 分析页面布局
根据UI稿我们可知,这个页面有一个底部切换的BottomBar,还有一个搜索框,一个横向的列表以及一个竖向的列表。

3. 定义数据
首先先定义数据
data class ImageItem(val name: String, val resId: Int)
导航栏的数据
val navList = listOf(
ImageItem("Home", R.drawable.ic_home),
ImageItem("Favorites", R.drawable.ic_favorite_border),
ImageItem("Profile", R.drawable.ic_account_circle),
ImageItem("Cart", R.drawable.ic_shopping_cart)
)
植物的数据
val gardenList = listOf(
ImageItem("Monstera", R.drawable.monstera),
ImageItem("Aglaonema", R.drawable.aglaonema),
ImageItem("Peace lily", R.drawable.peace_lily),
ImageItem("Fiddle leaf", R.drawable.fiddle_leaf),
ImageItem("Snake plant", R.drawable.snake_plant),
ImageItem("Pothos", R.drawable.pothos),
)
主题集合的数据
val themeList = listOf(
ImageItem("Desert chic", R.drawable.desert_chic),
ImageItem("Tiny terrariums", R.drawable.tiny_terrariums),
ImageItem("Jungle vibes", R.drawable.jungle_vibes),
ImageItem("Easy care", R.drawable.easy_care),
ImageItem("Statements", R.drawable.statements),
)
4. 实现底部Tab栏BottomBar
Scaffold是Android中的脚手架Scaffold,Compose 提供了大量基于 Material Design 的可组合项以及依赖项,旨在简化界面的构建。Scaffold 可以实现具有基本 Material Design 布局结构的界面,比如Drawer、FloatingActionButton 、 TopAppBar以及BottomBar
@Preview
@Composable
fun HomePage() {
Scaffold(bottomBar = {
BottomBar()
}) {
}
}
BottomBar里其实就是通过for循环navList,然后创建每一项的BottomNavigationItem
每个BottomNavigationItem里都包含一个icon和一个lable
@Preview(showBackground = true, backgroundColor = 0xFFFFFF)
@Composable
fun BottomBar() {
BottomNavigation(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
backgroundColor = pink100,
) {
navList.forEach {
val isSelected = "Home" == it.name
BottomNavigationItem(selected = isSelected, onClick = { }, icon = {
Image(
painter = painterResource(id = it.resId),
contentDescription = "",
modifier = Modifier.size(24.dp),
colorFilter = ColorFilter.tint(
if (isSelected) gray else Color(
0xff757575
)
)
)
}, label = {
Text(
text = it.name,
style = caption,
color = if (isSelected) gray else Color(0xff757575)
)
})
}
}
}
预览效果如下所示

5. 实现搜索框
搜索框其实就是OutlinedTextField,带边框的输入框,leadingIcon中传入Icon,用来显示搜索图标。
OutlinedTextField是material design包下的,说明它是个material design风格的组件
@Preview(showBackground = true)
@Composable
fun SearchBar() {
val keyword = remember { mutableStateOf("") }
Box(
modifier = Modifier
.height(96.dp)
.padding(top = 40.dp)
) {
OutlinedTextField(
value = keyword.value, onValueChange = {
keyword.value = it
}, modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp),
maxLines = 1,
placeholder = { Text(text = "Search", style = MaterialTheme.typography.body1) },
leadingIcon = {
Icon(
imageVector = Icons.Outlined.Search,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
}
)
}
}
OutlinedTextField针对样式进行了封装,我们直接用更底层的foundation包下的BasicTextField,也可以实现同样的效果
预览效果如下所示

6. 实现横向列表
首先实现Item
BloomRowTitle是标题
@Composable
private fun BloomRowTitle() {
Text(
text = "Browse themes",
modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 6.dp),
style = h1
)
}
然后实现横向列表
这里就用到LazyRow这个组件了
LazyRow和LazyColumn都是列表组件,用来替代传统View体系中的Recyclerview
LazyRow和LazyColumn内部都是基于LazyList组件实现的(这是一个internal的内部组件,我们无法直接使用)
可以看到传参中的content是一个LazyListScope.()->Unit
使用方式如下所示
LazyRow {
//添加一个Item
item {
Text("XXXXXXX")
}
//继续添加5个Item
item(5) {
Text("YYYYY"+it)
}
//继续添加一个List (等于添加了List.size个Item)
item(myList){ data ->
Text("$data.name $data.age")
}
}
知道了怎么用后,再来看下在本项目中怎么使用
代码如下所示
@Composable
fun BloomRowList() {
LazyRow(content = {
items(themeList.size) {
ThemeCard(themeList[it])
}
}, modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 3.dp))
}
ThemeCard是每一项的Item,实现如下
包含一个Box,一个Image,还有一个Text,最外层是一个Card,所以带有卡片阴影的效果
@Composable
fun ThemeCard(item: ImageItem) {
Card(elevation = 5.dp, modifier = Modifier.padding(6.dp)) {
Surface(
color = white
) {
Box(
modifier = Modifier
.height(136.dp)
.width(136.dp)
) {
Image(
painter = painterResource(id = item.resId),
contentDescription = null,
modifier = Modifier.height(96.dp),
contentScale = ContentScale.Crop
)
Text(
text = item.name,
style = h2,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
modifier = Modifier
.align(Alignment.BottomStart)
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp)
.fillMaxWidth()
)
}
}
}
}
进行组装
@Preview(showBackground = true, backgroundColor = 0xFFFFFF)
@Composable
fun BloomRowPreView() {
Column {
BloomRowTitle()
BloomRowList()
}
}
预览效果如下

7. 实现竖向的列表
首先实现Item
@Composable
fun BloomListTitle() {
Box(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
) {
Text(
text = "Design you home garden",
modifier = Modifier.align(Alignment.CenterStart),
style = h1,
)
Image(
imageVector = Icons.Default.FilterList,
contentDescription = null,
modifier = Modifier.align(Alignment.CenterEnd),
colorFilter = ColorFilter.tint(MaterialTheme.colors.onBackground)
)
}
}
然后实现竖向列表
@Composable
fun BloomList() {
LazyColumn(content = {
items(gardenList.size) {
ItemGarden(it == 0, gardenList[it])
}
})
}
来实现具体的Item,包含一个Image、Checkbox、主标题和副标题,以及一条分隔线。
最外层用的一个Box布局进行包裹,通过fillMaxWidth使其宽度设为最大。
@Composable
fun ItemGarden(checked: Boolean, item: ImageItem) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 16.dp)
.height(64.dp),
) {
Image(
painter = painterResource(id = item.resId),
contentDescription = "",
contentScale = ContentScale.Crop,
modifier = Modifier
.height(64.dp)
.width(64.dp)
.clip(shape = RoundedCornerShape(4.dp))
)
Column(modifier = Modifier.padding(start = 80.dp)) {
Text(text = item.name, style = h2, modifier = Modifier.padding(top = 12.dp))
Text(text = "This is a description", style = body1)
}
Checkbox(
checked = checked,
onCheckedChange = {},
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp)
)
Divider(
modifier = Modifier
.padding(start = 72.dp, end = 16.dp)
.align(Alignment.BottomStart)
)
}
}
这里的Checkbox暂时只是一个展示的用途,并无法让其真正进行点击
如果要让其可以点击,那么需要传入mutableStateOf给Checkbox,并在onCheckedChange回调的时候修改该mutableStateOf的值
var selectedby remember {
mutableStateOf(true)
}
Checkbox(
checked = selected,
onCheckedChange = {
selected = it
},
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp)
)
预览效果如下

8. 组装所有组件
这里我们使用Column竖向列表组装本文上述内容的组件
@Composable
fun HomePage() {
Scaffold(bottomBar = {
BottomBar()
}) {
Column {
SearchBar()
BloomRowTitle()
BloomRowList()
BloomListTitle()
BloomList()
}
}
}
最终显示效果如下

9. 小结
至此,我们就完成了主页的UI效果,下一篇文章,我们将来处理Compose页面间的跳转
Compose 项目实战 系列文章
Android Compose Bloom 项目实战 (一) : 项目说明与配置
Android Compose Bloom 项目实战 (二) : 欢迎页
Android Compose Bloom 项目实战 (三) : 登录页
Android Compose Bloom 项目实战 (四) : 主页
Android Compose Bloom 项目实战 (五) : 使用Navigation实现页面跳转
本文源码下载 : ComposeBloom
本文介绍了如何使用AndroidCompose开发主页界面,包括BottomBar的实现、搜索框的创建、横向和竖向列表的布局,以及Checkbox的展示。使用了Scaffold、BottomNavigationItem、OutlinedTextField、LazyRow和LazyColumn等组件。
3009

被折叠的 条评论
为什么被折叠?



