Jetpack Compose中的下拉刷新

前言

Jetpack Compose光下拉刷新,官方就提供了三种不同的方式,使用的依赖也不相同,特别的混乱。

所以在网络上看到的示例可能找不到依赖就是这个原因。

其中

  • swiperefresh 被废弃了
  • PullToRefreshContainer 需要更改依赖
  • PullRefresh 目前还没发布

也就是说只有前两种可以使用,如果不嫌弃代码中有废弃红线的标记,可以使用第一种,要么使用第二种。

swiperefresh

导入

1
implementation("com.google.accompanist:accompanist-swiperefresh:0.30.1")

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import android.util.Log
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Preview
@Composable
fun LazyListExample() {
val coroutineScope = rememberCoroutineScope()
var isRefreshing by remember {
mutableStateOf(false)
}
SwipeRefresh(state = rememberSwipeRefreshState(isRefreshing), modifier = Modifier
.fillMaxWidth()
.height(200.dp), onRefresh = {
isRefreshing = true
// 在协程作用域中启动异步任务
coroutineScope.launch {
// 执行异步操作,例如网络请求或数据库查询
Log.i("刷新", "")
delay(3000)
isRefreshing = false
}
}) {
//布局
LazyColumn(Modifier.fillMaxSize()) {
items(30) { index ->
Text(text = index.toString())
}
}
}
}

PullToRefreshContainer

把libs.version.toml中的

1
2
[libraries]
androidx-material3 = { group = "androidx.compose.material3", name = "material3"}

替换为

1
2
3
4
5
[versions]
material3Android = "1.2.1"

[libraries]
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }

build.gradle.kts中

1
implementation(libs.androidx.material3)

替换为

1
implementation(libs.androidx.material3.android)

两者的对比

material3是标准的库,能保证在各个平台上迁移代码,而material3-android是仅支持安卓的库,一些Android上新添加的组件会先在material3-android上发布,稳定后可能再在material3发布。

需要注意的是:

这两个库不能并存。

https://developer.android.google.cn/reference/kotlin/androidx/compose/material3/pulltorefresh/package-summary#PullToRefreshContainer

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ListItem
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay

@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun LazyListExample() {
var itemCount by remember { mutableStateOf(15) }
val state = rememberPullToRefreshState()
if (state.isRefreshing) {
LaunchedEffect(true) {
// fetch something
delay(1500)
itemCount += 5
state.endRefresh()
}
}
Box(
Modifier
.nestedScroll(state.nestedScrollConnection)
.fillMaxWidth()
.height(200.dp)
.clipToBounds()
) {
LazyColumn(Modifier.fillMaxSize()) {
if (!state.isRefreshing) {
items(itemCount) {
ListItem({ Text(text = "Item ${itemCount - it}") })
}
}
}
PullToRefreshContainer(
modifier = Modifier.align(Alignment.TopCenter),
state = state,
)
}
}

PullRefresh

Compose Material 1.3.0 才支持 但是1.3.0 还没正式发布。

https://developer.android.google.cn/jetpack/androidx/releases/compose-material3?hl=zh-cn

https://google.github.io/accompanist/swiperefresh/#migration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var refreshing by remember {
mutableStateOf(false)
}

val pullRefreshState = rememberPullRefreshState(refreshing, {

})

Box(Modifier.pullRefresh(pullRefreshState)) {
LazyColumn(Modifier.fillMaxSize()) {
items(30) { index ->
Text(text = index.toString())
}
}

PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
}

加载更多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
val listState = rememberLazyListState()
LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
items(itemCount) {
ListItem({ Text(text = "Item ${itemCount - it}") })
}
}
PullToRefreshContainer(
modifier = Modifier.align(Alignment.TopCenter),
state = state,
)

val isScrolledToBottom by remember(listState) {
derivedStateOf {
// 判断是否滚动到了底部
listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index == itemCount - 1
}
}

// 根据是否滚动到底部执行相应的操作
if (isScrolledToBottom) {
// 滚动到了底部
Log.i("滚动", "滚动到了底部")
}