Android Compose Bloom 项目实战 (四) : 主页

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

ScaffoldAndroid中的脚手架ScaffoldCompose 提供了大量基于 Material Design 的可组合项以及依赖项,旨在简化界面的构建。Scaffold 可以实现具有基本 Material Design 布局结构的界面,比如DrawerFloatingActionButtonTopAppBar以及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,用来显示搜索图标。
OutlinedTextFieldmaterial 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这个组件了
LazyRowLazyColumn都是列表组件,用来替代传统View体系中的Recyclerview
LazyRowLazyColumn内部都是基于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,包含一个ImageCheckbox主标题副标题,以及一条分隔线。
最外层用的一个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暂时只是一个展示的用途,并无法让其真正进行点击
如果要让其可以点击,那么需要传入mutableStateOfCheckbox,并在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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值