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

news2024/9/22 17:27:12

目录

  • 1.概述
  • 2.页面展示
    • 2.1 亮色主题
    • 2.2 深色主题
  • 3.页面拆分及实现
    • 3.1 主页的UI整体UI架构实现
    • 3.2 底部导航栏BottomBar的实现
    • 3.3 搜索栏SearchBar的实现
    • 3.4 Banner实现
    • 3.5 中间信息列表BloomInfoList的实现
  • 4.源码地址

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Microsoft Visual Studio 2022添加.NET Framework 4.6.2框架,然后说下.NET目标包的作用。

众所周知&#xff0c;Microsoft Visual Studio 2022不再支持.NET Framework 4.6以下的框架。从而导致前期使用老框架开发的某些应用无法打开&#xff08;打开时提示安装框架&#xff0c;但又安装不成功&#xff09;的情况出现。 前于如何安装.NET Framework 4.5及更早版本框架的…

Java中的字符串类

提示&#xff1a;字符串类是编程中最常用的一种数据类型&#xff0c;比较重要❗ 文章目录 前言一、字符串类创建对象方式静态创建动态创建 二、String字符串内容不可改变三、字符串常用方法length方法charAt方法substring方法indexOf与lastIndexOfindexOf方法lastIndexOf方法 替…

计算机基础--->数据结构(9)【并查集】

文章目录 并查集的概述并查集的主要用途并查集的实现创建和初始化集合查找当前元素的集合根节点判断两个元素是否处于同一集合合并两个集合对节点的路径进行压缩 并查集的概述 并查集是一种用于解决集合合并和查询问题的数据结构&#xff0c;主要用于实现有关集合的操作&#x…

Skywalking高级使用

Skywalking高级使用 RPC调用监控Mysql调用监控Skywalking常用插件获取追踪ID过滤指定的端点告警功能Skywalking原理Open Tracing介绍 RPC调用监控 Skywalking(6.5.0)支持的RPC框架有以下几种&#xff1a; (1) Dubbo 2.5.4 -> 2.6.0 (2) Dubbox 2.8.4 (3) Apache Dubbo 2.7.…

动态规划 DP (六) 字符串编辑

1.字符串编辑 字符串编辑问题是一类常见的问题&#xff0c;通常涉及对字符串进行插入、删除、替换等操作&#xff0c;以达到某种特定的目标。 常见的字符串编辑问题包括&#xff1a; 编辑距离&#xff08;Edit Distance&#xff09;&#xff1a;给定两个字符串&#xff0c;通…

最新抖音娱乐测评小程序源码 Thinkphp后端 抖音引流小程序

最新抖音娱乐测评小程序源码 thinkphp后端 抖音引流小程序 附搭建教程 测试环境 NginxPHP7.0MySQL5.6 网站运行目录设置为 /web 数据库配置文件 \source\application\database.php 后台登录地址 http://你的域名/index.php?s/admin/passport/login

python环境

卸载旧环境 wini 打开应用卸载 删除python解释器和pycharm 删除配置文件夹JetBrains C:\Users\CJC\AppData\Roaming\JetBrains 安装 安装python解释器 安装pycharm 查看或设置该项目的解释器和安装包 快捷键 全局搜索 双击shift 当前文件中搜索 ctrl f 查看函数…

MySQL数据库对象与数据备份和还原详解

目录 一、视图 1. 什么是视图 2. 视图与数据表的区别 3. 视图的优点 4. 创建视图 二、索引 1. 什么是索引 2. 为什么要使用索引 3. 索引优缺点 4. 何时不使用索引 5. 索引何时失效 6. 索引分类 6.1 普通索引 6.2 唯一索引 6.3 主键索引 6.4 组合索引 三、数据的…

RabbitMQ系列(25)--RabbitMQ搭建镜像队列

前言&#xff1a;如果RabbitMQ集群中只有一个Broker节点&#xff0c;那么该节点的失效将导致整体服务的临时性不可用&#xff0c;并且也可能会导致消息的丢失&#xff0c;虽然可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true&#xff0c;这样可以保证消息…

mysql 常用命令综合简单运用

目录 第一大题创建数据库创建用户表及约束字段修改位置修改字段数据类型修改字段名字添加字段修改表名字删除字段修改表的存储引擎 第二大题创建表及外键和其他约束删除外键约束和查找外键名 第三大题创建数据库创建用户同时授权一些功能修改用户的密码更新权限列表查看用户的权…

pytorch线性模型 学习前要学习的基础知识

跟着刘二大人学pytorch&#xff0c;补全一下我的基础缺失 1.numpy基础 import numpy as np from PIL import Image anp.array([1,2,3]) #生成一维数组 print(a) bnp.arange(1,4)#创建等差数组&#xff0c;默认等差是1&#xff0c;数组为1&#xff0c;2&#xff0c;3&#xff0…

spring 详解三 IOC(spring实例化及后处理器)

Spring实例化基本流程 Spring在容器初始化的时候&#xff0c;读取XMl配置&#xff0c;将其封装成BeanDefinition(Bean定义)对象&#xff0c;描述所有bean的信息 BeanDefinition会注册存储到beanDefinitionMap集合中 Spring框架遍历beanDefinitionMap&#xff0c;使用反射创建Be…

pycharm如何给一串中文快捷加引号(方法二)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 商人重利轻别离&#xff0c;前月浮梁买茶去。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银群【此类生物】问了一个Pycharm基础的问题&a…

SpringBoot配置动态定时任务

1.配置ScheduledTask 主要是实现SchedulingConfigurer&#xff0c;动态传入cron。 package com.hzl.boot.config;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Propert…

使用promise函数封装post请求,封装aes加解密方法,并进行请求头aes加密,封装sm2国密加解密,进行请求体数据加密,响应数据解密。

export default {async post(url, params { header:{}, data:{} }, showLoading true){if(showLoading){uni.showLoading({title:"加载中",mask:true})}let options{header:{...params.header},url:globalParams.basepathurl.url,data:{...params.data}}//渠道 ae…

Devops系列五(CI篇之pipeline libraray)jenkins将gitlab helm yaml和argocd 串联,自动部署到K8S

一、说在前面的话 本文是CI篇的上文&#xff0c;因为上一篇已经作了总体设计&#xff0c;就不再赘述&#xff0c;有需要的请看前文。 我们将演示&#xff0c;使用CI工具–jenkins&#xff0c;怎么和CD工具–argocd串联&#xff0c;重点是在Jenkins该怎么做。准备工作和argocd等…

C++常用库函数 5.输入和输出函数

函数名&#xff1a;fclose 函数原型&#xff1a;int fclose(FILE *stream)&#xff1b; 参数&#xff1a;streamFILE 结构的指针。 所需头文件&#xff1a;<cstdio> 返回值&#xff1a;如果该流成功关闭&#xff0c;fclose 返回0。如果出错&#xff0c;则返回 EOF。 功…

AI在金融领域的应用

AI金融领域 信贷业务 个人信贷单笔数额小、数量大&#xff0c;需要大量的人力和时间投入&#xff0c;信贷审核的数据也呈现出分散化、碎片化的特点。同时传统金融机构和互联网金融公司的风控环节中&#xff0c;普遍存在信息不对称、成本高、时效性差、效率低等问题&#xff0c…

动态规划之343 整数拆分(第6道)

题目&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例&#xff1a; 解法&#xff1a; 其实可以从1开始遍历 j &#xff0c;然后有两种…

Mysql之视图,索引,备份与恢复

目录 一&#xff0c;视图 1.视图是什么&#xff1f; 2.视图的重要性&#xff1f; 3.那些地方使用视图&#xff1f; 4.基本语法 二&#xff0c;索引 1.索引是什么&#xff1f; 2.索引的重要性&#xff1f; 3.索引的种类&#xff1a; 4.那些地方使用索引&#xff1f; 5.…