news 2026/5/1 5:02:16

Compose笔记(六十九)--Pager

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 滚动控制 滚动需在协程中调用

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 6:37:03

语义检索中的向量数据库选型指南:Milvus vs FAISS

语义检索中的向量数据库选型指南:Milvus vs FAISS 关键词:语义检索、向量数据库、Milvus、FAISS、近似最近邻搜索、向量相似度、企业级应用 摘要:在AI时代,语义检索已成为推荐系统、智能客服、多模态搜索等场景的核心技术。而实现高效语义检索的关键,是选择合适的向量数据…

作者头像 李华
网站建设 2026/4/25 5:35:16

3.28 PDF内容解析实战:mPLUG-DocOwl,让AI读懂PDF文档

3.28 PDF内容解析实战:mPLUG-DocOwl,让AI读懂PDF文档 引言 PDF文档解析是AI应用的重要场景,mPLUG-DocOwl是专门用于PDF解析的多模态模型。本文将深入解析PDF解析的实现方法。 一、PDF解析挑战 1.1 挑战概述 # PDF解析挑战 def pdf_parsing_challenges():""&q…

作者头像 李华
网站建设 2026/4/18 8:24:00

大模型智能体进阶:Skills层架构设计与最佳实践

本文详解了大模型智能体架构中的Skills层&#xff0c;作为LLM与工具间的逻辑抽象层&#xff0c;通过封装专业知识和工作流程&#xff0c;实现流程的刚性控制、Token节省和错误自愈。Skills将智能体从"单兵作战"转向"兵团作战"&#xff0c;通过"神经符…

作者头像 李华
网站建设 2026/4/12 16:37:08

2026年中国AI智能体营销趋势与发展报告蓝皮书|附191页PDF文件下载

本文提供完整版报告下载&#xff0c;请查看文后提示。以下为报告节选&#xff1a;......文│光华博思特本报告共计&#xff1a;191页。如欲获取完整版PDF文件如何学习大模型 AI &#xff1f;由于新岗位的生产效率&#xff0c;要优于被取代岗位的生产效率&#xff0c;所以实际上…

作者头像 李华
网站建设 2026/4/30 9:12:35

switch case 二分搜索风格

文章目录从汇编反向看 C 的 switch&#xff1a;二分搜索风格的案例分析1. 先看看源码2. 函数开头的栈和参数处理3. 第一层判断&#xff1a;围绕 1000 切分4. 小于 1000 的分支5. 大于 1000 的分支6. case 分支实现细节7. 从汇编“还原”成等价 C8. 为什么说这是“折半查找 / 二…

作者头像 李华
网站建设 2026/4/29 17:17:56

构建个人知识库工具分类与对比

在信息爆炸的2026年&#xff0c;个人知识库已成为知识工作者不可或缺的工具。它不仅帮助我们有效管理碎片化信息&#xff0c;还能通过结构化整理促进知识迁移与创新。本文将从功能特点、适用场景、核心优势三个维度&#xff0c;系统分析当前主流的个人知识库平台/软件/网站&…

作者头像 李华