1.概述

主页的页面比前面的欢迎页和登录页面要杂乱得多,假设运用传统的view,即运用xml布局的方法,咱们可能需要书写很多的代码,可是运用Compose UI,这一切都会变得很简略,有了前面的页面开发经历,咱们拿到这个主页的页面时首要想到的第一步便是拆分页面。然后将拆分后的页面运用Compose UI中对应的组件来完成。

2.页面展现

2.1 亮色主题

Android Compose UI实战练手----Google Bloom 主页实现(完结)

2.2 深色主题

Android Compose UI实战练手----Google Bloom 主页实现(完结)

3.页面拆分及完成

咱们的主页能够拆分为四个部分,分别是顶部的查找栏,然后是中间的banner和信息展现列表InfoList,以及底部的导航栏,拆分如下图所示:

Android Compose UI实战练手----Google Bloom 主页实现(完结)

咱们先写一个数据类和填充一些数据来辅佐编写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源码地址