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

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源码地址

猜你喜欢

转载自blog.csdn.net/zxj2589/article/details/131610864
今日推荐