前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式

Android Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式

作者头像
晨曦_LLW
发布2022-04-17 09:53:56
2K0
发布2022-04-17 09:53:56
举报

Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式

前言

  在上一篇文章中我们进行数据的存储和缓存的使用,这里我们进一步去优化这个业务。

正文

  首先我们想一个问题,那就是假如我一天不只是请求一次网络接口呢?要怎么办呢?难道我去应用管理中去清除本地数据然后再打开应用吗?那太傻了,那么就可以通过刷新的方式去更新当前的数据,同时这个数据还能存到本地数据库,这个业务看起来就更人性化一些。

一、下拉刷新

  通过标题就知道我要说什么内容了,在之前的Android开发中下拉刷新是常用的功能,而在Compose中也如此,只不过使用方式更简单一些,首先我们添加依赖版本。

① 添加依赖

打开项目的build.gradle,增加如下版本代码:

代码语言:javascript
复制
accompanist_version = '0.24.4-alpha'

目前我们只会用accompanist库中的刷新组件,到后面我们可能会用到accompanist库中的其他组件,因此我这里定义了accompanist_version,当然你也可以不定义。 增加位置如下图所示:

在这里插入图片描述
在这里插入图片描述

然后打开app下的build.gradle,增加如下依赖代码:

代码语言:javascript
复制
implementation "com.google.accompanist:accompanist-swiperefresh:$accompanist_version"

增加位置如下图所示:

在这里插入图片描述
在这里插入图片描述

② 使用

  使用其实非常的简单,下面我们改动一下MainActivity.kt中的BodyContent()函数,如下图所示:

在这里插入图片描述
在这里插入图片描述

原来这里只有一个LazyColumn,现在我在它的上面增加了一个SwipeRefresh,然后里面有两个必备的属性值,state和onRefresh,state是表示刷新状态,onRefresh表示刷新后执行的操作,这里我就弹一个Toast。下面我们运行一下看看:

在这里插入图片描述
在这里插入图片描述

③ 样式更改

刚才是最基本的使用,功能基本上有了,那么我们改一下它的样式。

在这里插入图片描述
在这里插入图片描述

这里配置了一指示器的样式:refreshTriggerDistance表示刷新触发的距离,scale表示刷新View的大小动画,默认是关闭的,我们打开。然后就是背景颜色,还有就是形状样式,下面再看看运行的效果:

在这里插入图片描述
在这里插入图片描述

我这里是放的很慢去进行的,为的就是看清楚这个动画效果。

二、刷新数据

  现在对于下拉刷新控件上的说明就结束了,我们要进入使用的环节了,实际上使用就是把onRefresh中执行方法换成我们实际的业务逻辑就行了,只不过通过下拉刷新来串联这个业务。

刷不刷新数据需要一个变量来控制,因此首先我们需要改动EpidemicNewsRepository.kt中的getEpidemicNews()函数,如下图所示:

在这里插入图片描述
在这里插入图片描述

这里就是增加一个参数,把这个参数作为是否需要请求网络数据的标准之一,当前没有刷新并且不是今天第一次请求网络,则从本地获取,如果有刷新,就从网络中请求数据。 然后我们需要改一下MainViewModel.kt

在这里插入图片描述
在这里插入图片描述

原来这里里面只有一行代码现在则多了一些,这里的代码很好理解,这里暴露一个方法给外部去调用,当getNews()函数的参数有改变时,就会触发repository.getEpidemicNews(it),然后页面上继续观察result的变化,有变化就会更新页面数据。

下面回到MainActivity.kt中,修改一下initData()函数中的方法,如下图所示:

在这里插入图片描述
在这里插入图片描述

这里我去掉了那个没有什么必要的临时变量,下面我们只需要在BodyContent()函数中的onRefresh的函数体中调用viewModel.getNews(true)方法即可实现下拉刷新功能。

在这里插入图片描述
在这里插入图片描述

下面我们再运行一下:

在这里插入图片描述
在这里插入图片描述

OK,这个地方就完成了。

三、复杂数据

  在实际开发中,很多都是A表中含有B表,而如果不需要建立那么多表,我们可以通过Room去处理,例如Desc数据类

在这里插入图片描述
在这里插入图片描述

它里面含有GlobalStatistics和ForeignStatistics,我们要在数据库中添加的话那么怎么样去操作呢?可以让这两个数据类成为Desc数据类的列。添加@Embedded注解,同时给Desc加上@Entity注解,同时主键也要添加。

在这里插入图片描述
在这里插入图片描述

下面我们再看GlobalStatistics和ForeignStatistics,他们里面的字段大部分相同,而在Room中不运行字段相同的情况,因此我们需要改一下列名,代码如下所示:

代码语言:javascript
复制
data class GlobalStatistics(
    @ColumnInfo(name = "global_currentConfirmedCount")
    val currentConfirmedCount: Int = 0,
    @ColumnInfo(name = "global_confirmedCount")
    val confirmedCount: Int = 0,
    @ColumnInfo(name = "global_curedCount")
    val curedCount: Int = 0,
    @ColumnInfo(name = "global_currentConfirmedIncr")
    val currentConfirmedIncr: Int = 0,
    @ColumnInfo(name = "global_confirmedIncr")
    val confirmedIncr: Int = 0,
    @ColumnInfo(name = "global_curedIncr")
    val curedIncr: Int = 0,
    @ColumnInfo(name = "global_deadCount")
    val deadCount: Int = 0,
    @ColumnInfo(name = "global_deadIncr")
    val deadIncr: Int = 0,
    @ColumnInfo(name = "global_yesterdayConfirmedCountIncr")
    val yesterdayConfirmedCountIncr: Int = 0
)

data class ForeignStatistics(
    @ColumnInfo(name = "foreign_currentConfirmedCount")
    val currentConfirmedCount: Int = 0,
    @ColumnInfo(name = "foreign_confirmedCount")
    val confirmedCount: Int = 0,
    @ColumnInfo(name = "foreign_curedCount")
    val curedCount: Int = 0,
    @ColumnInfo(name = "foreign_currentConfirmedIncr")
    val currentConfirmedIncr: Int = 0,
    @ColumnInfo(name = "foreign_suspectedIncr")
    val suspectedIncr: Int = 0,
    @ColumnInfo(name = "foreign_confirmedIncr")
    val confirmedIncr: Int = 0,
    @ColumnInfo(name = "foreign_curedIncr")
    val curedIncr: Int = 0,
    @ColumnInfo(name = "foreign_deadCount")
    val deadCount: Int = 0,
    @ColumnInfo(name = "foreign_deadIncr")
    val deadIncr: Int = 0,
    @ColumnInfo(name = "foreign_suspectedCount")
    val suspectedCount: Int = 0
)

因为Desc这里只是一个数据类,而不是List,所以我们每次保存和添加数据都是用同一个指定的ID。那么我们就需要将Desc的id改为var,这样后面我们就直接改这个id。

代码语言:javascript
复制
@PrimaryKey var id: Int = 0,

数据表改好之后,还有一个简单的方法,我们去dao包下增加一个DescDao接口,里面的代码如下:

代码语言:javascript
复制
@Dao
interface DescDao {

    @Query("SELECT * FROM `desc` WHERE id LIKE :id LIMIT 1")
    suspend fun getDesc(id: Int = 1): Desc

    @Insert
    suspend fun insert(desc: Desc?)

    @Query("DELETE FROM `desc`")
    suspend fun deleteAll()
}

这里很好理解,查询的时候就查询id=1的数据,那么我们在插入数据的时候就要设置desc的id为1, 最后在AppDatabase中配置

在这里插入图片描述
在这里插入图片描述

  看到这里是不是觉得很奇怪,这样肯定会报错,为什么呢?因为我之前最开始添加了一个表,之前的版本就是1,那么我这里新增了Desc表,那么对应的数据库版本就要迁移,你可以理解为升级,同时我们需要去添加一个Migrations,在这里去写新增数据表的SQL,这是很麻烦的,那么在调试中如果你只是自己调试而不需要发给别人的话,你可以这样做,就是把你现在的应用卸载,你再重新安装就可以了。省时省力,但是如果你是线上的项目那你还是老老实实的写迁移数据库的SQL,并且做好测试,当然了我们现在这样做只是方便开发测试,实际中不推荐你这么做,切记,切记。

下面回到EpidemicNewsRepository中,修改一下saveNews()函数,代码如下:

在这里插入图片描述
在这里插入图片描述

这里我们直接拿到newslistItem,因为news和desc都是在newslistItem中,注意看在插入desc的时候将id设置为1,那么我们在查询的时候要怎么做呢?修改一下getLocalForNews()函数,

在这里插入图片描述
在这里插入图片描述

你会发现我这里并没有传入参数,因为用了缺省值,当然了你也可以传入一个其他值,那么你在出入的时候也要做更改。

在这里插入图片描述
在这里插入图片描述

现在数据这一块就可以了,下面我们来做UI这一块的内容,需要用到Desc表中的数据。

四、复杂列表

① 更改返回数据

在之前主页面中就是显示一个数据列表,而没有其他的东西了,我们需要的desc和news属于同一级,因此我们需要上一级的数据。那么就需要改一下

在这里插入图片描述
在这里插入图片描述

看这个图应该就很好理解了,我们先拿到NewslistItem,然后再通过NewslistItem拿到news和desc,然后在BodyContent()函数中增加一个参数。

在这里插入图片描述
在这里插入图片描述

好了,到这里我们的数据就到了它应该去的地方,下面我们打印一下:

在这里插入图片描述
在这里插入图片描述

这里的Gson在前面就已经添加了依赖库,没有注意到的看前面的内容或者看源码,下面运行一下,看有没有日志打印:

在这里插入图片描述
在这里插入图片描述

很好,有日志,那么说明数据库没有问题,下面进行数据的显示。

② 增加item

下面我们在之前的列表上方再增加一个item,来看看怎么增加。

在这里插入图片描述
在这里插入图片描述

首先我们增加了一个item,然后再item里面去设置一个Card,然后设置宽度、高度、内填充、阴影、背景颜色。也就是说在最上方增加一个卡片式布局,下面我们来看布局里面的内容。

在这里插入图片描述
在这里插入图片描述

在Card中有一个Row,那么里面的内容就是横向,然后Row里面放了两个Column,表示里面有两个纵向,两个Column的设置一样,这里要注意的是weight(1f),表示权重,现在两个都是Column都是1f就是各占Row的50%,Column里面的其他两个配置就是Colum的内容上下居中。

那么我们再来看Column里的内容

在这里插入图片描述
在这里插入图片描述

这里的就很好理解了,基本上不用说什么了,如果你需要知道这些currentConfirmedIncr的含义,就去天行的API上去看,哪里有,下面我们运行一下:

在这里插入图片描述
在这里插入图片描述

你会看到一个列表有两个内容,内容不一样,但还是同一个列表,并且你的下拉刷新一样有效。

③ 嵌套

这里显示两个内容有点少,我们改一下

在这里插入图片描述
在这里插入图片描述

上面截图中的代码如下:

代码语言:javascript
复制
item {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(8.dp),
            elevation = 2.dp,
            backgroundColor = Color.White
        ) {
            Column {
                Row(modifier = Modifier.padding(12.dp)) {
                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,//设置垂直居中对齐
                        horizontalAlignment =  Alignment.CenterHorizontally//设置水平居中对齐
                    ) {
                        Text(text = "现存确诊人数")
                        Text(text = desc.currentConfirmedCount.toString(), fontSize = 24.sp, fontWeight = FontWeight.Bold)
                        Text(text = "较昨日 ${desc.currentConfirmedIncr}")
                    }

                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment =  Alignment.CenterHorizontally
                    ) {
                        Text(text = "累计确诊人数")
                        Text(text = desc.confirmedCount.toString(), fontSize = 24.sp, fontWeight = FontWeight.Bold)
                        Text(text = "较昨日 ${desc.currentConfirmedIncr}")
                    }
                }
                Row(modifier = Modifier.padding(12.dp)) {
                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,//设置垂直居中对齐
                        horizontalAlignment =  Alignment.CenterHorizontally//设置水平居中对齐
                    ) {
                        Text(text = "累计治愈人数")
                        Text(text = desc.curedCount.toString(), fontSize = 24.sp, fontWeight = FontWeight.Bold)
                        Text(text = "较昨日 ${desc.curedIncr}")
                    }

                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment =  Alignment.CenterHorizontally
                    ) {
                        Text(text = "累计死亡人数")
                        Text(text = desc.deadCount.toString(), fontSize = 24.sp, fontWeight = FontWeight.Bold)
                        Text(text = "较昨日 ${desc.deadIncr}")
                    }
                }
            }
        }
    }

我们把固定高度改了,让它自适应里面的内容高度,下面再运行一下:

在这里插入图片描述
在这里插入图片描述

如果这个代码写在BodyContent()函数中,那么会看起来代码很多,我们可以抽离一下,新增一个descItem函数,代码如下图所示:

在这里插入图片描述
在这里插入图片描述

五、网格布局

  从上面这里的代码我们已经实现了功能,但是会不会看上去不太智能呢?如果每一次添加都这样,那就太蠢了,因此我们可以用到网格布局。Compose的网格布局有横向的有纵向的,但还不稳定,因此就需要手动去写,这里可以这样去写,首先在MainActivity.kt中创建两个数据类

代码语言:javascript
复制
data class DescItem(var title: String, var current: Int, var yesterday: Int)

data class GroupItem(val descItem: DescItem?,val isEmpty: Boolean)

我们实际需要的数据并不太多,然后我们可以写一个descItemPlus()函数

代码语言:javascript
复制
private fun LazyListScope.descItemPlus(desc: Desc) {

}

首先因为数据是组装的,不是列表所以手动构建一个列表。

代码语言:javascript
复制
private fun LazyListScope.descItemPlus(desc: Desc) {
    //构建一个DescItemList
    val descList = mutableListOf<DescItem>().apply {
        add(DescItem("现存确诊人数", desc.currentConfirmedCount, desc.currentConfirmedIncr))
        add(DescItem("累计确诊人数", desc.confirmedCount, desc.confirmedIncr))
        add(DescItem("累计治愈人数", desc.curedCount, desc.curedIncr))
        add(DescItem("累计死亡人数", desc.deadCount, desc.deadIncr))
        add(DescItem("现存无症状人数", desc.seriousCount, desc.seriousIncr))
    }
}

现在数据源就有了,然后就是根据这个数据源去计算网格中的行和列。在descItemPlus函数中增加如下代码:

代码语言:javascript
复制
	//网格Items
    val gradItems = mutableListOf<List<GroupItem>>()
    var index = 0
    //网格是行与列组成,显示2列
    val columnNum = 2
    //计算显示几行
    val rowNum = ceil(descList.size.toFloat() / columnNum).toInt()
    //遍历行
    for (i in 0 until rowNum) {
        val rowItems = mutableListOf<GroupItem>()
        //遍历列
        for (j in 0 until columnNum) {
            if (index.inc() <= descList.size) {
                rowItems.add(GroupItem(descList[index++],false))
            }
        }

        //如果未填充满,则显示占位
        val itemEmpty = columnNum - rowItems.size
        for (j in 0 until itemEmpty) {
            rowItems.add(GroupItem(null,true))
        }
        gradItems.add(rowItems)
    }

最后在descItemPlus()函数中我们显示每一个item。

代码语言:javascript
复制
	//显示数据
    items(gradItems) { gradItem ->
        Row {
            for (gird in gradItem) {
                if (gird.isEmpty) {
                    Box(modifier = Modifier.weight(1f))
                } else {
                    Box(modifier = Modifier.weight(1f)) {
                        Card(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(8.dp),
                            elevation = 2.dp,
                            backgroundColor = Color.White
                        ) {
                            val descItem = gird.descItem!!
                            Column(
                                modifier = Modifier.padding(12.dp),
                                verticalArrangement = Arrangement.Center,//设置垂直居中对齐
                                horizontalAlignment = Alignment.CenterHorizontally//设置水平居中对齐
                            ) {
                                Text(text = descItem.title)
                                Text(
                                    text = descItem.current.toString(),
                                    fontSize = 24.sp,
                                    fontWeight = FontWeight.Bold
                                )
                                Text(text = "较昨日 ${descItem.yesterday}")
                            }
                        }
                    }
                }
            }
        }
    }

这样就可以实现功能了,下面我们调用一下:

在这里插入图片描述
在这里插入图片描述

然后运行一下:

在这里插入图片描述
在这里插入图片描述

实际中根据自己的需求去更改使用的方式,,这个descItemPlus()函数的代码会保留,这里我还是用之前的descItem()函数,因为我需要去更改文字的不同样式。

六、修改样式

首先在colors.xml中增加一些色值

代码语言:javascript
复制
	<color name="red">#FC3538color>
    <color name="dark_red">#B00000color>
    <color name="green">#1BB394color>
    <color name="gray_black">#656565color>
    <color name="gray">#989898color>

下面我们来修改一下descItem()函数中的控件样式。

在这里插入图片描述
在这里插入图片描述

这里先来改第一个,这里修改了文字的大小,然后设置了颜色,和填充,最主要的是下面这个buildAnnotatedString,它可以对一个Text中的不同内容做不同的样式设置,然后这里还有一个拓展函数addSymbols(),代码如下:

代码语言:javascript
复制
fun Int.addSymbols(): String = if (this > 0.0 && this != 0) "+$this" else "$this"

可以直接写在MainActivity.kt,也可以单独建一个kotlin文件去写,这个拓展函数主要就是如果我们的int数据是正数,还要大于零,就添加一个+,负责就是原来的数据,返回String。那么其他的都可以照着改一下,我这里贴一下descItem()函数的代码:

代码语言:javascript
复制
private fun LazyListScope.descItem(desc: Desc) {
    item {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(8.dp),
            elevation = 2.dp,
            backgroundColor = Color.White
        ) {
            Column {
                Row(modifier = Modifier.padding(12.dp)) {
                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,//设置垂直居中对齐
                        horizontalAlignment = Alignment.CenterHorizontally//设置水平居中对齐
                    ) {
                        Text(text = "现存确诊人数", fontSize = 12.sp)
                        Text(
                            text = desc.currentConfirmedCount.toString(),
                            fontSize = 28.sp,
                            fontWeight = FontWeight.Bold,
                            color = colorResource(id = R.color.red),
                            modifier = Modifier.padding(0.dp, 4.dp)
                        )
                        Text(buildAnnotatedString {
                            withStyle(style = SpanStyle(fontSize = 12.sp, color = colorResource(id = R.color.gray))) {
                                append("较昨日 ")
                            }
                            withStyle(style = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Bold)) {
                                append(desc.currentConfirmedIncr.addSymbols())
                            }
                        })
                    }

                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Text(text = "累计确诊人数", fontSize = 12.sp)
                        Text(
                            text = desc.confirmedCount.toString(),
                            fontSize = 28.sp,
                            fontWeight = FontWeight.Bold,
                            color = colorResource(id = R.color.dark_red),
                            modifier = Modifier.padding(0.dp, 4.dp)
                        )
                        Text(buildAnnotatedString {
                            withStyle(style = SpanStyle(fontSize = 12.sp, color = colorResource(id = R.color.gray))) {
                                append("较昨日 ")
                            }
                            withStyle(style = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Bold)) {
                                append(desc.confirmedIncr.addSymbols())
                            }
                        })
                    }
                }
                Row(modifier = Modifier.padding(12.dp)) {
                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,//设置垂直居中对齐
                        horizontalAlignment = Alignment.CenterHorizontally//设置水平居中对齐
                    ) {
                        Text(text = "累计治愈人数", fontSize = 12.sp)
                        Text(
                            text = desc.curedCount.toString(),
                            fontSize = 28.sp,
                            fontWeight = FontWeight.Bold,
                            color = colorResource(id = R.color.green),
                            modifier = Modifier.padding(0.dp, 4.dp)
                        )
                        Text(buildAnnotatedString {
                            withStyle(style = SpanStyle(fontSize = 12.sp, color = colorResource(id = R.color.gray))) {
                                append("较昨日 ")
                            }
                            withStyle(style = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Bold)) {
                                append(desc.curedIncr.addSymbols())
                            }
                        })
                    }

                    Column(
                        modifier = Modifier.fillMaxSize().weight(1f),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Text(text = "累计死亡人数", fontSize = 12.sp)
                        Text(
                            text = desc.deadCount.toString(),
                            fontSize = 28.sp,
                            fontWeight = FontWeight.Bold,
                            color = colorResource(id = R.color.gray_black),
                            modifier = Modifier.padding(0.dp, 4.dp)
                        )
                        Text(buildAnnotatedString {
                            withStyle(style = SpanStyle(fontSize = 12.sp, color = colorResource(id = R.color.gray))) {
                                append("较昨日 ")
                            }
                            withStyle(style = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Bold)) {
                                append(desc.deadIncr.addSymbols())
                            }
                        })
                    }
                }
            }
        }
    }
}

下面运行一下:

在这里插入图片描述
在这里插入图片描述

七、源码

GitHub:GoodNews CSDN:GoodNews_4.rar

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式
  • 前言
  • 正文
    • 一、下拉刷新
      • ① 添加依赖
      • ② 使用
      • ③ 样式更改
    • 二、刷新数据
      • 三、复杂数据
        • 四、复杂列表
          • ① 更改返回数据
          • ② 增加item
          • ③ 嵌套
        • 五、网格布局
          • 六、修改样式
            • 七、源码
            相关产品与服务
            数据库
            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档