当前位置: 首页 > news >正文

Compose笔记(六十九)--Pager

这一节主要了解一下Compose中的Pager,在Jetpack Compose开发中,Pager是用于实现滑动页面集合的核心组件,支持水平(HorizontalPager)和垂直(VerticalPager)方向的滑动,能够灵活管理页面内容、状态和交互。简单总结:

API:
HorizontalPager/VerticalPager:核心组件,分别实现横向 / 纵向翻页
rememberPagerState:创建并记忆 Pager 状态,包含当前页码、滑动偏移等
PagerScope:页面作用域,提供 pageOffset 等页面滑动状态参数
PageSize:定义页面尺寸
PagerSnapDistance:定义滑动后吸附到页面的距离

场景:
1 图片轮播 在电商、新闻等应用中,顶部展示多张图片并自动轮播,用户可手动滑动切换。
2 引导页 应用首次启动时展示多页引导内容,用户滑动浏览后进入主界面。
3 分类标签页 顶部标签栏切换时,下方内容同步滑动

栗子:

implementation("io.coil-kt:coil-compose:2.5.0")
// 权限 <uses-permission android:name="android.permission.INTERNET" />
import androidx.compose.runtime.Composable import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PageSize import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.LaunchedEffect 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.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.scale import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import kotlinx.coroutines.delay import kotlinx.coroutines.launch data class PagerItem( val id: Int, val title: String, val imageUrl: String, val bgColor: androidx.compose.ui.graphics.Color ) fun Float.format(digits: Int): String = "%.${digits}f".format(this) @Composable fun PagerDemo() { val pagerData = listOf( PagerItem(1, "商品A", "https://picsum.photos/800/400?random=1", androidx.compose.ui.graphics.Color(0xFF6495ED)), PagerItem(2, "商品B", "https://picsum.photos/800/400?random=2", androidx.compose.ui.graphics.Color(0xFF90EE90)), PagerItem(3, "商品C", "https://picsum.photos/800/400?random=3", androidx.compose.ui.graphics.Color(0xFFFFB6C1)), PagerItem(4, "商品D", "https://picsum.photos/800/400?random=4", androidx.compose.ui.graphics.Color(0xFFFFD700)) ) Surface(modifier = Modifier.fillMaxSize()) { val pagerState = rememberPagerState( initialPage = 0, pageCount = { pagerData.size } ) val coroutineScope = rememberCoroutineScope() var slideOffset by remember { mutableStateOf(0.0f) } LaunchedEffect(pagerState.currentPage, pagerState.currentPageOffsetFraction) { slideOffset = pagerState.currentPage + pagerState.currentPageOffsetFraction } Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = "滑动进度:${slideOffset.format(2)}", fontSize = 16.sp, modifier = Modifier.padding(16.dp) ) HorizontalPager( state = pagerState, modifier = Modifier .weight(1f) .padding(horizontal = 20.dp), pageSize = PageSize.Fill, pageSpacing = 16.dp, contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 20.dp) ) { pageIndex -> val item = pagerData[pageIndex] val pageOffset = pagerState.currentPageOffsetFraction val scale by animateFloatAsState( targetValue = if (pageIndex == pagerState.currentPage) 1f else 0.9f, label = "pageScale" ) val alpha by animateFloatAsState( targetValue = if (pageIndex == pagerState.currentPage) 1f else 0.7f, label = "pageAlpha" ) var isLoading by remember { mutableStateOf(true) } LaunchedEffect(pageIndex) { delay(300) isLoading = false } Box( modifier = Modifier .fillMaxSize() .scale(scale) .alpha(alpha) .background(item.bgColor, MaterialTheme.shapes.medium) .padding(16.dp), contentAlignment = Alignment.Center ) { if (isLoading) { Text(text = "加载中...", color = androidx.compose.ui.graphics.Color.White) } else { Column( horizontalAlignment = Alignment.CenterHorizontally ) { Image( painter = rememberAsyncImagePainter(model = item.imageUrl), contentDescription = item.title, modifier = Modifier .size(200.dp, 150.dp) .padding(bottom = 16.dp), contentScale = ContentScale.Crop ) Text( text = item.title, fontSize = 20.sp, color = androidx.compose.ui.graphics.Color.White ) } } } } Column( modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Row( horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(bottom = 16.dp) ) { pagerData.forEachIndexed { index, _ -> val isSelected = index == pagerState.currentPage Box( modifier = Modifier .size(if (isSelected) 12.dp else 8.dp) .background( color = if (isSelected) androidx.compose.ui.graphics.Color.Blue else androidx.compose.ui.graphics.Color.Gray, shape = CircleShape ) ) } } Row( horizontalArrangement = Arrangement.spacedBy(16.dp) ) { Button( onClick = { coroutineScope.launch { if (pagerState.currentPage > 0) { pagerState.animateScrollToPage(pagerState.currentPage - 1) } } }, enabled = pagerState.currentPage > 0 ) { Text(text = "上一页") } Button( onClick = { coroutineScope.launch { if (pagerState.currentPage < pagerData.size - 1) { pagerState.animateScrollToPage(pagerState.currentPage + 1) } } }, enabled = pagerState.currentPage < pagerData.size - 1 ) { Text(text = "下一页") } } } } } }
import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.VerticalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter @Composable fun PagerDemo() { val imageUrls = listOf( "https://picsum.photos/800/1200?random=1", "https://picsum.photos/800/1200?random=2", "https://picsum.photos/800/1200?random=3" ) val pagerState = rememberPagerState( initialPage = 0, pageCount = { imageUrls.size } ) Surface(modifier = Modifier.fillMaxSize()) { VerticalPager( state = pagerState, modifier = Modifier.fillMaxSize(), pageSize = androidx.compose.foundation.pager.PageSize.Fill ) { pageIndex -> Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Image( painter = rememberAsyncImagePainter(model = imageUrls[pageIndex]), contentDescription = "商品图片${pageIndex + 1}", modifier = Modifier .fillMaxSize() .padding(20.dp), contentScale = ContentScale.Crop ) Text( text = "${pageIndex + 1}/${imageUrls.size}", fontSize = 20.sp, color = Color.White, modifier = Modifier .background(Color.Black.copy(alpha = 0.5f)) .padding(8.dp) .align(Alignment.BottomCenter) ) } } } }

注意:
1 页面预加载与优化 默认仅加载可见页面,通过beyondViewportPageCount设置屏幕外预加载页面数
2 状态管理与滚动监听 使用LaunchedEffect(pagerState.currentPage)监听页面变化,避免在pageContent中直接监听导致重复重组。
3 滚动控制 滚动需在协程中调用

http://www.cnnetsun.cn/news/543716.html

相关文章:

  • 【图像分割】黎曼流形特征空间的多视角聚类遥感图像分割【含Matlab源码 14899期】
  • 不同 AI 生成 2026 年工作计划 PPT 的使用门槛对比
  • node.js基于vue的实验室器材耗材设备信息管理系统_x50ntw8y
  • 入梦工具箱
  • 中药材原料口碑排行榜:哪些药材最受欢迎?
  • 腾讯天美AI团队重新定义语言模型训练:精确还是多样?
  • 亲测好用!继续教育9个AI论文网站深度测评
  • PX4实战(十一):PX4运动规划模块(flight mode manager)详解
  • 提示工程架构师推荐:社交网络提示设计的10个高效工具
  • 斯坦福大学等发布:AI助手在企业政策执行上“偏科“得如此严重
  • FreeSWITCH 简单图形化界面51 - 拨号应用 Bridge 介绍
  • Qt OpenGL 生成Mipmap技术详解
  • 2026继续教育必备10个降AI率工具测评榜单
  • A.每日一题——1161. 最大层内元素和
  • AU48 语音处理模组:全双工通话设备的性能升级优选方案
  • 1.线性switch case语句逆向特征
  • HY-MT1.5-1.8B模型微调教程:特定领域适应性训练步骤
  • AutoGPT十年演进(2015–2025)
  • RAG十年演进(2015–2025)
  • HY-MT1.5-1.8B轻量部署实战:手机端也能跑的翻译模型
  • 把异性哄到笑开花的搞笑甜话术
  • HY-MT1.5-1.8B降本部署案例:边缘设备上实现95%精度保留方案
  • HY-MT1.5-1.8B推理速度优化:TensorRT加速部署教程
  • Hunyuan-HY-MT1.5对比评测:同规模翻译模型中为何领先商业API?
  • 前端老铁别再混用 Promises 和 Observables 了!搞懂区别少踩80%
  • HY-MT1.5术语干预实战:品牌名/产品名统一翻译部署教程
  • HY-MT1.5-7B vs 商业API性能对比:多语言翻译部署案例实测
  • HY-MT1.5-1.8B响应时间优化:批处理+缓存机制部署教程
  • AI开发者必看:Hunyuan HY-MT1.5开源镜像使用全解析
  • HY-MT1.5-1.8B部署避坑指南:边缘计算资源分配实战建议