目录
1.概述
主页的页面比前面的欢迎页和登录页面要复杂得多,假设使用传统的view,即使用xml布局的方式,我们可能需要书写很多的代码,但是使用Compose UI,这一切都会变得很简单,有了前面的页面开发经验,我们拿到这个主页的页面时首先想到的第一步就是拆分页面。然后将拆分后的页面使用Compose UI中对应的组件来实现。
2.页面展示
2.1 亮色主题
2.2 深色主题
3.页面拆分及实现
我们的主页可以拆分为四个部分,分别是顶部的搜索栏,然后是中间的banner和信息展示列表InfoList,以及底部的导航栏,拆分如下图所示:
我们先写一个数据类和填充一些数据来辅助编写Home页面,代码如下:
data class ImageItem(val name:String,val resID:Int)
val bloomBannerList = listOf<ImageItem>(
ImageItem("Desert chic", R.drawable.desert_chic),
ImageItem("Tiny terrariums",R.drawable.tiny_terrariums),
ImageItem("Jungle Vibes",R.drawable.jungle_vibes)
)
val bloomInfoList = listOf<ImageItem>(
ImageItem("Monstera",R.drawable.monstera),
ImageItem("Aglaonema",R.drawable.aglaonema),
ImageItem("Peace lily",R.drawable.peace_lily),
ImageItem("Fiddle leaf tree",R.drawable.fiddle_leaf),
ImageItem("Desert chic",R.drawable.desert_chic),
ImageItem("Tiny terrariums",R.drawable.tiny_terrariums),
ImageItem("Jungle Vibes",R.drawable.jungle_vibes)
)
val navList = listOf<ImageItem>(
ImageItem("Home",R.drawable.ic_home),
ImageItem("Favorites",R.drawable.ic_favorite),
ImageItem("Profile",R.drawable.ic_account_circle),
ImageItem("Cart",R.drawable.ic_shopping_cart),)
上面代码中的资源可以导文末给的源码地址中去相应目录下拿
3.1 主页的UI整体UI架构实现
主页的整体UI架构布局我们可以使用前面学过的Scaffold组件,快速搭建,如下所示:
@Composable
fun HomePage() {
Scaffold(bottomBar = {
BottomBar() //底部导航栏 }) {
Column(
Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
.padding(horizontal = 16.dp)
) {
SearchBar() // 搜索栏
BloomRowBanner() // banner 列表
BloomInfoList() // 中间信息展示列表
}
}
}
3.2 底部导航栏BottomBar的实现
底部导航栏的实现非常简单,我们直接使用Compose提供的BottomNavigation
组件实现就可以了,代码如下所示:
@Composable
fun BottomBar() {
BottomNavigation(
elevation = 16.dp,
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
backgroundColor = MaterialTheme.colors.secondary
) {
navList.forEach {
BottomNavigationItem(
onClick = {
/*TODO*/ },
icon = {
Icon(
painterResource(id = it.resID),
contentDescription = null,
modifier = Modifier.size(24.dp)
)
},
label = {
Text(
text = it.name,
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.onPrimary
)
}, selected = ("Home" == it.name)
)
}
}
}
3.3 搜索栏SearchBar的实现
对于搜索栏,可以使用TextField实现,TextField是一个Material组件,会携带默认的背景色和底部边框颜色,所以我们还需对TextField进行额外的颜色配置。代码如下所示:
@Composable
fun SearchBar() {
Box {
TextField(
value = "",
onValueChange = {
},
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.clip(RoundedCornerShape(4.dp)),
leadingIcon = {
Icon(
painter = rememberVectorPainter(
image = ImageVector.vectorResource(R.drawable.ic_search),
),
contentDescription = "search",
modifier = Modifier.size(18.dp),
tint = Color.Gray
)
},
placeholder = {
Text(
text = "Search",
style = MaterialTheme.typography.body1,
color = Color.Gray
)
},
colors = TextFieldDefaults.outlinedTextFieldColors(
backgroundColor = Color.White,
unfocusedBorderColor = Color.White,// 未选中时的下边框颜色
focusedBorderColor = Color.White // 选中时下边框颜色
)
)
}
}
3.4 Banner实现
要实现Banner的展示,我们需要由一个Text组件和LazyRow组件组合而成。banner内容的展示我们可以编写一个子元素模板组件PlantCard组件来辅助实现Home主页,代码如下所示:
@Composable
fun PlantCard(plant: ImageItem) {
Card(
modifier = Modifier
.size(136.dp)
.clip(RoundedCornerShape(4.dp))
) {
Column {
Image(
painterResource(
id = plant.resID
),
contentScale = ContentScale.Crop,
contentDescription = "image",
modifier = Modifier
.fillMaxWidth()
.height(96.dp)
)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp)
) {
Text(
text = plant.name,
style = MaterialTheme.typography.h2,
color = MaterialTheme.colors.primary,
modifier = Modifier
.fillMaxWidth()
.paddingFromBaseline(top = 24.dp, bottom = 16.dp)
)
}
}
}
}
然后在我们编写Banner 列表展示的时候就可以使用PlantCard了,如下:
@Composable
fun BloomRowBanner() {
Column {
Box(modifier = Modifier.fillMaxWidth()) {
Text(
text = "Browse themes",
style = MaterialTheme.typography.h1,
color = MaterialTheme.colors.primary,
modifier = Modifier
.fillMaxWidth()
.paddingFromBaseline(top = 32.dp)
)
}
Spacer(modifier = Modifier.height(16.dp))
LazyRow(modifier = Modifier.height(136.dp)) {
items(bloomBannerList.size) {
if (it != 0) {
// 每个子元素之间水平间距为8.dp
Spacer(modifier = Modifier.width(8.dp))
}
PlantCard(plant = bloomBannerList[it])
}
}
}
}
3.5 中间信息列表BloomInfoList的实现
这个组件和前面的Banner列表展示差不多,只是这个组件的右侧有一个小图标,所以我们可以使用Text组件和Icon组件组合成Row组件,再让Row组件与LazyColumn组件组合成BloomInfoList组件。
与前面一样,我们先编写一个子元素组件模板DesignCard,代码如下所示:
@Composable
fun DesignCard(plant: ImageItem) {
Row(modifier = Modifier.fillMaxWidth()) {
Image(
painterResource(id = plant.resID),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(4.dp))
)
Spacer(modifier = Modifier.width(16.dp))
Column {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
)
{
Column {
Text(
text = plant.name,
style = MaterialTheme.typography.h2,
color = MaterialTheme.colors.primary,
modifier = Modifier.paddingFromBaseline(top = 24.dp)
)
Text(
text = "这是描述。。。。。。。",
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.primary,
)
}
Checkbox(
checked = false, onCheckedChange = {
},
modifier = Modifier
.padding(top = 24.dp)
.size(24.dp),
colors = CheckboxDefaults.colors(checkmarkColor = Color.White)
)
}
// 每个子元素下面画一根线
Divider(
color = Color.Gray,
modifier = Modifier.padding(top = 16.dp),
thickness = 0.5.dp
)
}
}
}
然后利用DesignCard实现我们要展示的BloomInfoList组件,代码如下:
@Composable
fun BloomInfoList() {
Column {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Design your home garden",
style = MaterialTheme.typography.h1,
color = MaterialTheme.colors.primary,
modifier = Modifier.paddingFromBaseline(top = 40.dp)
)
Icon(
painterResource(id = R.drawable.ic_filter_list),
contentDescription = "filter",
modifier = Modifier
.padding(top = 24.dp)
.size(24.dp)
)
}
Spacer(modifier = Modifier.height(16.dp))
LazyColumn(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(bottom = 56.dp)
) {
items(bloomInfoList.size) {
if (it != 0) {
Spacer(modifier = Modifier.height(8.dp))
}
DesignCard(plant = bloomInfoList[it])
}
}
}
}
至此,Goole Bloom的主页就开发完成了。
4.源码地址
到此为止,Compose UI 实战练手项目就结束了,感兴趣的读者一定要自己动手敲一遍,我也是跟着书上敲的代码,发现了好多书上的代码在真实的环境中不能运行,有的是展示错误。然后改正这些错误后收获颇丰,所以建议读者也去手动敲一遍,这样的化感触和记忆都会更深。另外本系列的页面颜色是自己乱配的。读者可以自行去修改
GooleBloom源码地址