Jetpack Compose中的分页器Pager的使用

前言

如需以左右或上下方式浏览内容,您可以分别使用 HorizontalPagerVerticalPager可组合项。

这些可组合项的功能与视图系统中的 ViewPager类似。

官方文档:

https://android-dot-google-developers.gonglchuangl.net/jetpack/compose/layouts/pager?hl=zh-cn

基本示例

1
2
3
4
5
6
7
8
9
10
11
// Display 10 items
val pagerState = rememberPagerState(pageCount = {
10
})
HorizontalPager(state = pagerState) { page ->
// Our page content
Text(
text = "Page: $page",
modifier = Modifier.fillMaxWidth()
)
}

页面切换添加效果

该示例实现了切换时页面从半透明到不透明的效果。

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.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import com.xhkjedu.xh_control_appstore.vm.AppViewModel
import kotlin.math.absoluteValue

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MPager(appViewModel: AppViewModel, pagerState: PagerState, callback: (page: Int) -> Unit) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize(),
verticalAlignment = Alignment.Top,
beyondBoundsPageCount = 10,
) { page ->
Box(
Modifier
.fillMaxSize()
.graphicsLayer {
val pageOffset = ((pagerState.currentPage - page) + pagerState.currentPageOffsetFraction).absoluteValue
alpha = 1f - pageOffset.coerceIn(0f, 1f)
}
) {
if (page == 0) {
AppListView(appViewModel.appList)
} else {
AppListView(appViewModel.appList2)
}
}
}

LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
Log.i("Page change", "Page changed to $page")
callback(page)
}
}
}

滚动到某页

无动画滚动

1
2
3
4
5
6
7
8
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
coroutineScope.launch {
pagerState.scrollToPage(5)
}
}, modifier = Modifier.align(Alignment.BottomCenter)) {
Text("Jump to Page 5")
}

带动画滚动

1
2
3
4
5
6
7
8
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(5)
}
}, modifier = Modifier.align(Alignment.BottomCenter)) {
Text("Jump to Page 5")
}

页面切换监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val pagerState = rememberPagerState(pageCount = {
10
})

LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
Log.d("Page change", "Page changed to $page")
}
}

VerticalPager(
state = pagerState,
) { page ->
Text(text = "Page: $page")
}

页面指示器

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
val pagerState = rememberPagerState(pageCount = {
4
})
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize()
) { page ->
// Our page content
Text(
text = "Page: $page",
)
}
Row(
Modifier
.wrapContentHeight()
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 8.dp),
horizontalArrangement = Arrangement.Center
) {
repeat(pagerState.pageCount) { iteration ->
val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray
Box(
modifier = Modifier
.padding(2.dp)
.clip(CircleShape)
.background(color)
.size(16.dp)
)
}
}

项目实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MPager(appViewModel: AppViewModel, pagerState: PagerState, callback: (page: Int) -> Unit) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize(),
verticalAlignment = Alignment.Top,
beyondBoundsPageCount = 2
) { page ->
Log.i("page", page.toString())
if (page == 0) {
AppListView(appViewModel.appList)
} else {
AppListView(appViewModel.appList2)
}
}

LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
Log.i("Page change", "Page changed to $page")
callback(page)
}
}
}

注意

默认情况下,分页器只会加载屏幕上显示的页面。如需在屏幕外加载更多页面,请将 beyondBoundsPageCount 设置为大于零的值。

使用

1
2
3
4
5
6
7
val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f,
) {
// provide pageCount
2
}

点击切换页面

1
2
3
4
5
val coroutineScope = rememberCoroutineScope()

coroutineScope.launch {
pagerState.animateScrollToPage(index)
}