官方页面一、概念类似于 ViewPager1.4 版本之前需要借助 accompanis 库底层基于 LazyColumn、LazyRow 实现在使用上也基本相同。默认情况下 HorizontalPager 占据屏幕的整个宽度VerticalPager 会占据整个高度。HorizontalPager()Composablefun HorizontalPager(state: PagerState,modifier: Modifier Modifier,contentPadding: PaddingValues PaddingValues(0.dp), //内容内边距pageSize: PageSize PageSize.Fill, //页面填充模式填充满Fill自适应FixedbeyondViewportPageCount: Int PagerDefaults.BeyondViewportPageCount, //当前页面前后预加载的页面数量pageSpacing: Dp 0.dp, //两个分页之间的间隙verticalAlignment: Alignment.Vertical Alignment.CenterVertically,flingBehavior: TargetedFlingBehavior PagerDefaults.flingBehavior(state state), //用于滚动后手势的flingBehavioruserScrollEnabled: Boolean true, //是否允许通过用户手势或辅助功能进行滚动即使禁用PagerState.scroll仍然可以使用它以编程方式滚动reverseLayout: Boolean false, //反转分页顺序key: ((index: Int) - Any)? null, //指定唯一标识优化增删分页重组问题pageNestedScrollConnection: NestedScrollConnection PagerDefaults.pageNestedScrollConnection(state, Orientation.Horizontal), //一个嵌套的ScrollConnection用于指示此Pager如何使用嵌套列表。默认行为将使Pager消耗所有嵌套的delta。snapPosition: SnapPosition SnapPosition.Start, //吸附位置overscrollEffect: OverscrollEffect? rememberOverscrollEffect(),pageContent: Composable PagerScope.(page: Int) - Unit,)rememberPagerState()Composablefun rememberPagerState(initialPage: Int 0, //起始分页的索引FloatRange(from -0.5, to 0.5) initialPageOffsetFraction: Float 0f, //起始页面的偏移程度pageCount: () - Int, //分页数量): PagerState二、使用2.1 简单使用val pagerState rememberPagerState { 10 } //10是页面数量 HorizontalPager( state pagerState, modifier Modifier.size(100.dp) ) { page - // 每一页的内容比如显示个文本 Text( text Page: $page, modifier Modifier.fillMaxSize() ) }2.2 离屏加载更多页面Pager 中的页面都是懒加载的只在需要时才会进行组合和布局。这是一个核心的性能特性当用户滚动时Pager 会移除不再需要的页面保持低内存占用。将 beyondBoundsPageCount 属性设为 0 的整数会在当前页面左右各加载相同数量的页面。虽然让滑动更顺畅但是注意做数据懒加载处理避免一下就直接加载好几个页面的数据。2.3 控制页面滚动使用 rememberPagerState() 创建一个 PagerState 对象并将其作为 state 参数传递给分页器。在 CoroutineScope 中对此状态调用 PagerState.scrollToPage()带动画跳转使用 PagerState.animateScrollToPage()。前进state.animateScrollToPage(min(state.currentPage 1, state.pageCount - 1))后退state.animateScrollToPage(max(state.currentPage - 1, 0))val pagerState rememberPagerState { 10 } HorizontalPager( state pagerState modifier Modifier.size(100.dp) ) { page - Text( text Page: $page modifier Modifier.fillMaxSize() ) } val coroutineScope rememberCoroutineScope() Button( modifier Modifier.align(Alignment.BottomCenter) onClick { coroutineScope.launch { pagerState.scrollToPage(5) //普通跳转 // pagerState.animateScrollToPage(5) //带动画跳转 } } ) { Text(跳到页面5) }自动滚动LaunchedEffect(Unit) { while (true) { delay(3000) pagerState.animateScrollToPage( (pagerState.currentPage 1) % pagerState.pageCount ) } }2.4 添加页面指示器2.4.1 小圆点通过 pagerState.pageCount 获取页面数量并绘制自定义指示器。使用 pagerState.currentPage 获取当前显示页面的索引改变对应指示器的颜色。Row( modifier Modifier .align(Alignment.BottomCenter) .fillMaxWidth() .padding(bottom 2.dp), horizontalArrangement Arrangement.Center ) { repeat(pagerState.pageCount) { index - val color if (pagerState.currentPage index) Colors.black else Colors.gray Box(modifier Modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(10.dp) ) } }2.4.2 Tab栏如果 text 没设置颜色就会应用 selectedContentColor、unselectedContentColor 的颜色。Composable fun Demo() { val tabList listOf(最新,广场,问答,项目) val pagerState rememberPagerState { tabList.size } val coroutineScope rememberCoroutineScope() Column( modifier Modifier.fillMaxSize() ) { TabRow( modifier Modifier .padding(vertical 10.dp) .fillMaxWidth() .height(20.dp), selectedTabIndex pagerState.currentPage, containerColor AppColors.transparent, indicator {}, divider {} ) { tabList.forEachIndexed { index, title - Tab( text { Text( text title, fontSize if (pagerState.currentPage index) 15.sp else 15.sp, fontWeight if (pagerState.currentPage index) FontWeight.ExtraBold else FontWeight.Bold) }, selected pagerState.currentPage index, selectedContentColor AppTheme.colors.textPrimary, unselectedContentColor AppTheme.colors.textSecondary, onClick { coroutineScope.launch { pagerState.scrollToPage(index) } } ) } } HorizontalPager( state pagerState, beyondBoundsPageCount 1, pageSpacing Dimension.contentMargin ) { index - when (index) { 0 - { NewestPage() } 1 - { SquarePage() } 2 - { QaPage() } 3 - { ProjectPage() } } } } }2.5 多页面同时显示2.5.1 修改页面大小默认情况下PageSize.FillPager 认为页面应该填充满整个分页大小即便设置了固定大小也会被拉伸成 fillMaxSize() 效果。换成 PageSize.Fixed 一个分页可以显示多个页面适合要显示多个项目或特定大小的项目。默认设置固定大小PageSize.Fixed(200.dp)2.5.2 调整首尾对齐通过调整吸附位置 snapPosition 能选择首/尾对齐。默认 SnapPosition.StartSnapPosition.CenterSnapPosition.End2.6 提示还有下一个/上一个内容2.6.1 内容边距 ContentPaddingcontentPadding 在滑动的时候是能覆盖到的分配了额外的滑动空间而 Modifier.padding() 是滑动不到的这个边距在任何时候都会显示。contentPadding 最常见的用途之一是让下一个和上一个页面能够窥探到屏幕上。这向用户传达了一个信号还有更多内容可以探索。在内容起始和结束位置添加 16.dp 的内边距contentPadding PaddingValues(horizontal 16.dp)。2.6.2 页面间距 PageSpacingcontentPadding 影响 Pager 内容的外边缘而 pageSpacing 用于定义单个页面之间的间隙。pageSpacing (16).dppageSpacing (-16).dp
Compose 组件 - 分页器 HorizontalPager、VerticalPager
官方页面一、概念类似于 ViewPager1.4 版本之前需要借助 accompanis 库底层基于 LazyColumn、LazyRow 实现在使用上也基本相同。默认情况下 HorizontalPager 占据屏幕的整个宽度VerticalPager 会占据整个高度。HorizontalPager()Composablefun HorizontalPager(state: PagerState,modifier: Modifier Modifier,contentPadding: PaddingValues PaddingValues(0.dp), //内容内边距pageSize: PageSize PageSize.Fill, //页面填充模式填充满Fill自适应FixedbeyondViewportPageCount: Int PagerDefaults.BeyondViewportPageCount, //当前页面前后预加载的页面数量pageSpacing: Dp 0.dp, //两个分页之间的间隙verticalAlignment: Alignment.Vertical Alignment.CenterVertically,flingBehavior: TargetedFlingBehavior PagerDefaults.flingBehavior(state state), //用于滚动后手势的flingBehavioruserScrollEnabled: Boolean true, //是否允许通过用户手势或辅助功能进行滚动即使禁用PagerState.scroll仍然可以使用它以编程方式滚动reverseLayout: Boolean false, //反转分页顺序key: ((index: Int) - Any)? null, //指定唯一标识优化增删分页重组问题pageNestedScrollConnection: NestedScrollConnection PagerDefaults.pageNestedScrollConnection(state, Orientation.Horizontal), //一个嵌套的ScrollConnection用于指示此Pager如何使用嵌套列表。默认行为将使Pager消耗所有嵌套的delta。snapPosition: SnapPosition SnapPosition.Start, //吸附位置overscrollEffect: OverscrollEffect? rememberOverscrollEffect(),pageContent: Composable PagerScope.(page: Int) - Unit,)rememberPagerState()Composablefun rememberPagerState(initialPage: Int 0, //起始分页的索引FloatRange(from -0.5, to 0.5) initialPageOffsetFraction: Float 0f, //起始页面的偏移程度pageCount: () - Int, //分页数量): PagerState二、使用2.1 简单使用val pagerState rememberPagerState { 10 } //10是页面数量 HorizontalPager( state pagerState, modifier Modifier.size(100.dp) ) { page - // 每一页的内容比如显示个文本 Text( text Page: $page, modifier Modifier.fillMaxSize() ) }2.2 离屏加载更多页面Pager 中的页面都是懒加载的只在需要时才会进行组合和布局。这是一个核心的性能特性当用户滚动时Pager 会移除不再需要的页面保持低内存占用。将 beyondBoundsPageCount 属性设为 0 的整数会在当前页面左右各加载相同数量的页面。虽然让滑动更顺畅但是注意做数据懒加载处理避免一下就直接加载好几个页面的数据。2.3 控制页面滚动使用 rememberPagerState() 创建一个 PagerState 对象并将其作为 state 参数传递给分页器。在 CoroutineScope 中对此状态调用 PagerState.scrollToPage()带动画跳转使用 PagerState.animateScrollToPage()。前进state.animateScrollToPage(min(state.currentPage 1, state.pageCount - 1))后退state.animateScrollToPage(max(state.currentPage - 1, 0))val pagerState rememberPagerState { 10 } HorizontalPager( state pagerState modifier Modifier.size(100.dp) ) { page - Text( text Page: $page modifier Modifier.fillMaxSize() ) } val coroutineScope rememberCoroutineScope() Button( modifier Modifier.align(Alignment.BottomCenter) onClick { coroutineScope.launch { pagerState.scrollToPage(5) //普通跳转 // pagerState.animateScrollToPage(5) //带动画跳转 } } ) { Text(跳到页面5) }自动滚动LaunchedEffect(Unit) { while (true) { delay(3000) pagerState.animateScrollToPage( (pagerState.currentPage 1) % pagerState.pageCount ) } }2.4 添加页面指示器2.4.1 小圆点通过 pagerState.pageCount 获取页面数量并绘制自定义指示器。使用 pagerState.currentPage 获取当前显示页面的索引改变对应指示器的颜色。Row( modifier Modifier .align(Alignment.BottomCenter) .fillMaxWidth() .padding(bottom 2.dp), horizontalArrangement Arrangement.Center ) { repeat(pagerState.pageCount) { index - val color if (pagerState.currentPage index) Colors.black else Colors.gray Box(modifier Modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(10.dp) ) } }2.4.2 Tab栏如果 text 没设置颜色就会应用 selectedContentColor、unselectedContentColor 的颜色。Composable fun Demo() { val tabList listOf(最新,广场,问答,项目) val pagerState rememberPagerState { tabList.size } val coroutineScope rememberCoroutineScope() Column( modifier Modifier.fillMaxSize() ) { TabRow( modifier Modifier .padding(vertical 10.dp) .fillMaxWidth() .height(20.dp), selectedTabIndex pagerState.currentPage, containerColor AppColors.transparent, indicator {}, divider {} ) { tabList.forEachIndexed { index, title - Tab( text { Text( text title, fontSize if (pagerState.currentPage index) 15.sp else 15.sp, fontWeight if (pagerState.currentPage index) FontWeight.ExtraBold else FontWeight.Bold) }, selected pagerState.currentPage index, selectedContentColor AppTheme.colors.textPrimary, unselectedContentColor AppTheme.colors.textSecondary, onClick { coroutineScope.launch { pagerState.scrollToPage(index) } } ) } } HorizontalPager( state pagerState, beyondBoundsPageCount 1, pageSpacing Dimension.contentMargin ) { index - when (index) { 0 - { NewestPage() } 1 - { SquarePage() } 2 - { QaPage() } 3 - { ProjectPage() } } } } }2.5 多页面同时显示2.5.1 修改页面大小默认情况下PageSize.FillPager 认为页面应该填充满整个分页大小即便设置了固定大小也会被拉伸成 fillMaxSize() 效果。换成 PageSize.Fixed 一个分页可以显示多个页面适合要显示多个项目或特定大小的项目。默认设置固定大小PageSize.Fixed(200.dp)2.5.2 调整首尾对齐通过调整吸附位置 snapPosition 能选择首/尾对齐。默认 SnapPosition.StartSnapPosition.CenterSnapPosition.End2.6 提示还有下一个/上一个内容2.6.1 内容边距 ContentPaddingcontentPadding 在滑动的时候是能覆盖到的分配了额外的滑动空间而 Modifier.padding() 是滑动不到的这个边距在任何时候都会显示。contentPadding 最常见的用途之一是让下一个和上一个页面能够窥探到屏幕上。这向用户传达了一个信号还有更多内容可以探索。在内容起始和结束位置添加 16.dp 的内边距contentPadding PaddingValues(horizontal 16.dp)。2.6.2 页面间距 PageSpacingcontentPadding 影响 Pager 内容的外边缘而 pageSpacing 用于定义单个页面之间的间隙。pageSpacing (16).dppageSpacing (-16).dp