Compose Indication:点击效果设置

Compose Indication:打造独特点击效果的秘密武器

在Compose开发中,大家可能都碰到过Indication,不少人第一次接触它,是在想去掉Material默认的点击水波纹效果的时候。要是在AI工具里搜“怎么去掉水波纹效果”,会得到这样一段代码:

Box(modifier = Modifier.size(200.dp).clickable(// 去除指示效果indication = null, interactionSource = null) {// 点击事件处理逻辑},contentAlignment = Alignment.Center) {Text(text = "No Ripple Click", color = Color.Black)}

indication参数设成null,水波纹效果就没了。这背后是怎么实现的呢?先看看Indication的注释。Indication代表在一些交互发生时出现的视觉效果,像组件被按下时的涟漪效果,或者被聚焦时的高亮显示。想自定义Indication,可以参考IndicationNodeFactory,它能实现更高效的指示效果。Indication一般通过LocalIndication在整个层级结构中提供,开发者可以自定义LocalIndication,改变组件(比如clickable)的默认指示效果。从这里能看出,Indication就是用来实现点击、聚焦、拖动等组件效果的,有点像传统View系统里的selector,但它的功能可要强大得多。

在传统View系统里,selector能根据组件的不同状态,指定不同的资源或颜色。不过,要实现交互效果,得知道组件的当前状态。而Indication本身没办法获取组件的交互状态,这时就需要Interaction来帮忙了。

在很多情况下,开发普通组件时,我们不用关心Compose组件是怎么解读用户操作的。比如创建一个Button,通过Modifier.clickable就能判断用户有没有点击,设置好onClick代码就行,不用管是点击屏幕还是用键盘操作。但要是想自定义组件对用户行为的响应方式,Interaction就派上用场了。

当用户和界面组件交互时,系统会生成很多Interaction事件。比如用户点击按钮,按钮会生成PressInteraction.Press;在按钮范围内松开手指,会生成PressInteraction.Release,表示点击完成;要是手指拖出按钮范围再松开,就会生成PressInteraction.Cancel,代表点击取消。这些互动事件没有预设的含义,也不解读操作顺序和优先级。

如果想跟踪互动来扩展组件功能,比如让按钮按下时变色,最简单的办法就是观察互动状态。InteractionSource提供了很多方法来获取各种互动状态,像调用InteractionSource.collectIsPressedAsState(),就能知道按钮有没有被按下:

val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()Button(onClick = { /* do something */ },interactionSource = interactionSource
) {Text(if (isPressed) "Pressed!" else "Not pressed")
}

除了collectIsPressedAsState(),Compose还提供了collectIsFocusedAsState()collectIsDraggedAsState()collectIsHoveredAsState(),这些都是基于InteractionSource低级API的便捷方法,不过在某些场景下,直接用低级函数会更好。

了解完Interaction,再回到Indication。下面讲讲怎么用Indication创建和应用可复用的自定义效果。

IndicationNodeFactory是用来创建Modifier.Node实例的工厂,这些实例可以是有状态或无状态的,能从CompositionLocal检索值,和其他Modifier.Node一样。Modifier.indication是个修饰符,用于绘制Indication组件。Modifier.clickable这类高级互动修饰符能直接接受指示参数,既能发出Interaction,又能绘制视觉效果,所以简单场景下,用Modifier.clickable就行,不一定非要Modifier.indication

来看个例子,把点击缩放效果用Indication实现,步骤如下:

  1. 创建负责应用缩放效果的Modifier.Node。这个节点要观察互动来源,和之前的示例类似,但它会直接启动动画,而不是把互动转成状态。节点需要实现DrawModifierNode,重写ContentDrawScope#draw(),用Compose的图形API渲染缩放效果,调用drawContent()绘制应用Indication的组件,注意一定要调用,不然组件不会显示。
private class ScaleNode(private val interactionSource: InteractionSource) :Modifier.Node(), DrawModifierNode {var currentPressPosition: Offset = Offset.Zeroval animatedScalePercent = Animatable(1f)private suspend fun animateToPressed(pressPosition: Offset) {currentPressPosition = pressPositionanimatedScalePercent.animateTo(0.9f, spring())}private suspend fun animateToResting() {animatedScalePercent.animateTo(1f, spring())}override fun onAttach() {coroutineScope.launch {interactionSource.interactions.collectLatest { interaction ->when (interaction) {is PressInteraction.Press -> animateToPressed(interaction.pressPosition)is PressInteraction.Release -> animateToResting()is PressInteraction.Cancel -> animateToResting()}}}}override fun ContentDrawScope.draw() {scale(scale = animatedScalePercent.value,pivot = currentPressPosition) {this@draw.drawContent()}}
}
  1. 创建IndicationNodeFactory,它的任务就是创建新节点实例。如果没有配置参数,工厂可以是个对象:
object ScaleIndication : IndicationNodeFactory {override fun create(interactionSource: InteractionSource): DelegatableNode {return ScaleNode(interactionSource)}override fun equals(other: Any?): Boolean = other === ScaleIndicationoverride fun hashCode() = 100
}
  1. Modifier.clickable内部用了Modifier.indication,要让组件带有ScaleIndication的点击效果,直接把Indication作为clickable的参数就行:
Box(modifier = Modifier.size(100.dp).clickable(onClick = {},indication = ScaleIndication,interactionSource = null).background(Color.Blue),contentAlignment = Alignment.Center
) {Text("Hello!", color = Color.White)
}

这样就实现了一个按住缩放的交互效果,这个Indication可以用在任何Composable函数上。Indication能定义一套交互效果并应用到各种组件上,如果项目里有标准的交互效果设计,用Indication准没错。欢迎大家一起交流,有问题可以在评论区留言或者私信我!

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

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

相关文章

Docker build 会在本地产生巨大的文件

Docker build 会在本地产生巨大的文件, 比如 用 这个命令列出本地镜像 docker images 可见size都是很大的, 到docker目录下,看到ext4.vhdx的大小 80多G 那只能用这个命令把不用的镜像删掉了: (rmi后面是镜像id&a…

台式机电脑组装---电脑机箱与主板接线

台式机电脑组装—电脑机箱与主板接线 1、机箱连接主板的跳线一般主要有USB 2.0、USB 3.0、前置音频接口(HD_AUDIO)以及POWER SW、RESET SW、POWER LED、HDD LED四个主板跳线,这些跳线分别的含义如下。 RESET SW:机箱重启按键;注&#xff1a…

【虚幻引擎UE5】SpawnActor生成Character实例不执行AI Move To,未初始化AIController的原因和解决方法

虚幻引擎版本:5.5.4 问题描述 刚创建的Third Person项目里,定义一个BP_Enemy蓝图,拖拽到场景中产生的实例会追随玩家,但SpawnActor产生的实例会固定不动。BP_Enemy蓝图具体设计如下: BP_Enemy的Event Graph ​​ 又定义…

跨平台RTSP高性能实时播放器实现思路

跨平台RTSP高性能实时播放器实现思路 目标:局域网100ms以内超低延迟 一、引言 现有播放器(如VLC)在RTSP实时播放场景中面临高延迟(通常数秒)和资源占用大的问题。本文提出一种跨平台解决方案,通过网络层…

HTTP 失败重试(重发)方案

在 Qt 网络开发中,使用 QNetworkAccessManager 进行 HTTP 请求时,可能会遇到网络超时、服务器错误等情况。为了提高请求的可靠性,可以实现 HTTP 失败重试(重发) 机制。下面介绍几种常见的 失败重发方案: 单…

大白话详细解读React框架的diffing算法

1. Diffing 算法是什么? Diffing 算法是 React 用来比较虚拟 DOM(Virtual DOM)树的一种算法。它的作用是找出前后两次渲染之间的差异(diff),然后只更新这些差异部分,而不是重新渲染整个页面。 …

【Linux内核系列】:动静态库详解

🔥 本文专栏:Linux 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 有些鸟儿是注定是关不住的,因为它们的每一片羽翼都沾满了自由的光辉 ★★★ 本文前置知识: 编译与链接的过程…

深度解读DeepSeek部署使用安全(48页PPT)(文末有下载方式)

深度解读DeepSeek:部署、使用与安全 详细资料请看本解读文章的最后内容。 引言 DeepSeek作为一款先进的人工智能模型,其部署、使用与安全性是用户最为关注的三大核心问题。本文将从本地化部署、使用方法与技巧、以及安全性三个方面,对Deep…

【详细解决】pycharm 终端出现报错:“Failed : 无法将“Failed”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。

昨天在终端一顿操作后突然打开pycharm时就开始报错: 无法将“Failed”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:1 字符: 1 Failed to act…

【电路笔记】-D型触发器

D型触发器 文章目录 D型触发器1、概述2、主从D触发器3、使用D型触发器进行分频4、D触发器作为数据锁存器5、透明数据锁存器6、总结D型触发器是一种改进的置位-复位触发器,通过增加一个反相器来防止S和R输入处于相同的逻辑电平。 1、概述 D型触发器克服了基本SR NAND门双稳态电…

智慧共享杆:城市智能化管理的 “多面手”

智慧共享杆:城市智能化管理的 “多面手” 在智慧城市建设的进程中,智慧共享杆凭借其多功能与集约化的特性,逐渐成为城市基础设施建设领域的重点关注对象。它不仅革新了传统路灯杆的固有模式,更为城市的高效管理与便捷服务开创了全…

【Tips】pip临时换源

pip换源网站 用法: pip install xxx库 -i https://pypi.tuna.tsinghua.edu.cn/simple https://pypi.tuna.tsinghua.edu.cn/simplehttps://mirrors.aliyun.com/pypi/simplehttps://pypi.douban.com/simplehttps://pypi.mirrors.ustc.edu.cn/simplehttps://mirrors.…

AcWing 838:堆排序 ← 数组模拟

【题目来源】 https://www.acwing.com/problem/content/840/ 【题目描述】 输入一个长度为 n 的整数数列,从小到大输出前 m 小的数。 【输入格式】 第一行包含整数 n 和 m。 第二行包含 n 个整数,表示整数数列。 【输出格式】 共一行,包含…

Microchip AN1477中关于LLC数字补偿器的疑问

最近在学习Microchip的AN1477关于LLC的功率级传递函数推导及数字补偿器设计,对其中的2P2Z数字补偿器的系数有一些困惑。我在MATLAB中运行了源程序提供的VMC_LLC.m文件,发现有些地方和AN1477中的结果不一致。现在把相关有疑问的地方列举出来,也…

【原创】使用ElasticSearch存储向量实现大模型RAG

一、概述 检索增强生成(Retrieval-Augmented Generation,RAG)已成为大型语言模型(LLM)应用的重要架构,通过结合外部知识库来增强模型的回答能力,特别是在处理专业领域知识、最新信息或企业私有数…

分享下web3j 常见用法

转账 fun sendEthTransaction(privateKey: String,toAddress: String,amount: BigDecimal) {//chainIdval chainId:Long 1//url 可以从https://chainlist.org/里面获取可用节点//eth转账,bnb同理,但需发送到bnb对应节点val url "https://xxx"…

《真·滕王阁序》

《滕工阁序》 西二旗故地,后厂新府。 星分百度网易,地接腾讯阿里。 襟PRD而带OKR,控需求以引撕逼。 物华天宝,龙光射工卡芯片;人杰地灵,徐孺坐产品经理之榻。 工位雾列,码农星驰。 台积电…

云盘搭建笔记

报错问题: No input file specified. 伪静态 location / {if (!-e $request_filename) { rewrite ^(.*)$ /index.php/$1 last;break;} } location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php/$1 last; break; } } 设…

如何打造安全稳定的亚马逊采购测评自养号下单系统?

在当今的电商领域,亚马逊作为全球领先的在线购物平台,其商品种类繁多,用户基数庞大,成为了众多商家和消费者的首选。而对于一些需要进行商品测评或市场调研的用户来说,拥有一个稳定、安全的亚马逊账号体系显得尤为重要…

c语言数据结构 单循环链表设计(完整代码)

单链表的增删查改代码: 1.创建结构体 // 结构体类型的创建 struct node {int data; // 数据域struct node *next; // 指针域 };2.创建节点,节点的存储在malloc申请的空间内,也就是堆空间。 // 创建节点 struct node *create_node…