当前位置:网站首页>Compose实战-实现一个带下拉加载更多功能的LazyColumn
Compose实战-实现一个带下拉加载更多功能的LazyColumn
2022-08-01 19:33:00 【失落夏天】
前言:
LazyColumn类似于android原生中的listview,用来加载列表中的数据。
本文主要记录如何使用compose去实现一个带下拉加载更多功能的列表。
一.使用LazyColumn实现基本列表功能
首先构建ComposeListActivity,用来装载界面。
主要包含以下几块:
list:mutableStateListOf类型,可被观测状态的数据源。
ListGreeting:LazyColumn绘制的方法,展示list中的数据。
ListMessageCard:类似于ItemView,用来显示每一行的数据
loadMore:模拟加载更多数据的方法。
代码如下:
/**
* @author lxl
* compose带下拉加载更多功能的lazyColumn
*/
class ComposeListActivity : ComponentActivity() {
private val list = mutableStateListOf<String>();
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadMore()
setContent {
DemoClientTheme {
// A surface container using the 'background' color from the theme
ListGreeting()
}
}
}
@SuppressLint("UnrememberedMutableState")
@Composable
fun ListGreeting() {
Log.i("lxltest","ListGreeting")
val state = rememberLazyListState()
Row(
Modifier
.padding(5.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
LazyColumn(Modifier.padding(5.dp), state = state) {
items(list) { name ->
ListMessageCard(name)
}
}
LoadMoreListHandler(listState = state) {
Toast.makeText([email protected], "加载中,请稍后", Toast.LENGTH_SHORT).show()
loadMore()
}
}
}
@Composable
fun ListMessageCard(name: String) {
Row(modifier = Modifier.padding(all = 12.dp)) {
Spacer(modifier = Modifier.width(10.dp))
Column {
Text(
text = name,
color = MaterialTheme.colors.secondaryVariant,
style = MaterialTheme.typography.subtitle2,
fontSize = 16.sp
)
Spacer(modifier = Modifier.width(12.dp))
}
}
}
private fun loadMore() {
val start = list.size
Log.i("lxltest", "加载start:${start}到${start + 30}")
list.apply {
for (i in 0 until 30) {
add("text${start + i}")
}
}
}
}
二.使用remember记录状态
compose区别于传统的安卓布局,compose是并不是使用回调的概念,而使用的一种观察者的模式。并且默认是无状态的,所以我们要使用remember来记录状态并设置到LazyColumn中去。
首先生成一个loadMore的续体,如果loadMore的状态发生了变化,则会进行回调。而状态是否发生变化,则是我们上面的remember中的判断。
我们这里判断如果距离底部还有1个时触发状态的变化,返回true。
val loadMore = remember {
derivedStateOf {
val layoutInfo = listState.layoutInfo
val totalItemsCount = layoutInfo.totalItemsCount
val lastVisibleItemIndex = (layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0) + 1
val b = lastVisibleItemIndex > (totalItemsCount - buffer)
Log.i(
"lxltest",
"lastVisibleItemIndex:${lastVisibleItemIndex},totalItemsCount:${totalItemsCount},buffer:${buffer},result:${b}"
)
b
}
}
然后把loadMore的续体传入LaunchedEffect中,这时候如果loadMore.value的状态发生变化,则会调用传进来的onLoaderMore进行通知
LaunchedEffect(loadMore)
{
snapshotFlow { loadMore.value }
.distinctUntilChanged()
.collect {
onLoaderMore()
}
}
最完这些工作后,发现果然是可以了,拉拉到30,60临界点时,会自动加载新的数据。
但是也发现一个问题,就是每次加载数据,不是加载30条,而是60条。这是为何?
三.排查解决问题
在collect中加入日志辅助排查,终于找到了问题。原来loadMore状态变化通知时,会通知两次,第一次是状态发生变化的通知,此时it=true。有一次it=false,我怀疑有可能是修改完成的一个回调。具体没有去追踪,所以这里简单做一下it判断就可以了。完整代码如下:
@Composable
fun LoadMoreListHandler(listState: LazyListState, buffer: Int = 1, onLoaderMore: () -> Unit) {
val loadMore = remember {
derivedStateOf {
val layoutInfo = listState.layoutInfo
val totalItemsCount = layoutInfo.totalItemsCount
val lastVisibleItemIndex = (layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0) + 1
val b = lastVisibleItemIndex > (totalItemsCount - buffer)
Log.i(
"lxltest",
"lastVisibleItemIndex:${lastVisibleItemIndex},totalItemsCount:${totalItemsCount},buffer:${buffer},result:${b}"
)
b
}
}
LaunchedEffect(loadMore)
{
snapshotFlow { loadMore.value }
.distinctUntilChanged()
.collect {
if (it) {
onLoaderMore()
}
}
}
}
四.项目地址
完整代码地址:
GitHub - aa5279aa/android_all_demo: 一直觉得研究各种技术,一个个demo的下载运行太费劲了,为什么不能有一个所有新技术的融合体demo呢?项目为此而生
边栏推荐
- 安装GBase 8c数据库的时候,报错显示“Resource:gbase8c already in use”,这怎么处理呢?
- Website construction process
- C#/VB.NET Extract table from PDF
- Win11怎么安装语音包?Win11语音包安装教程
- BN BatchNorm + BatchNorm的替代新方法KNConvNets
- Library website construction source code sharing
- Heavy cover special | build the first line of defense, cloud firewall offensive and defensive drills best practices
- 使用常见问题解答软件的好处有哪些?
- PHP 安全最佳实践
- SQL的 ISNULL 函数
猜你喜欢
随机推荐
To drive efficient upstream and downstream collaboration, how can cross-border B2B e-commerce platforms release the core value of the LED industry supply chain?
Try compiling QT test on Allwinner V853 development board
Win11如何删除升级包?Win11删除升级包的方法
Greenplum数据库源码分析——Standby Master操作工具分析
57: Chapter 5: Develop admin management services: 10: Develop [get files from MongoDB's GridFS, interface]; (from GridFS, get the SOP of files) (Do not use MongoDB's service, you can exclude its autom
Pytorch模型训练实用教程学习笔记:四、优化器与学习率调整
Keras深度学习实战——交通标志识别
英国伦敦大学|眼科强化学习:潜在应用和实施挑战
锐捷交换机基础配置
MySQL开发技巧——存储过程
nacos安装与配置
Heavy cover special | intercept 99% malicious traffic, reveal WAF offensive and defensive drills best practices
明日盛会|ApacheCon Asia 2022 Pulsar 技术议题一览
SaaS管理系统的应用优势在哪里?如何高效提升食品制造业数智化发展水平?
PROE/Croe如何编辑已完成的草图,让其再次进入草绘状态
SENSORO成长伙伴计划 x 怀柔黑马科技加速实验室丨以品牌力打造To B企业影响力
百度无人驾驶商业化已“上路”
Pytorch模型训练实用教程学习笔记:二、模型的构建
MySQL中超键、主键及候选键的区别是什么
Shell script topic (07): file from cfs to bos