news 2026/3/17 7:30:29

Compose笔记(七十)--movableContentWithReceiverOf

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Compose笔记(七十)--movableContentWithReceiverOf

这一节主要了解一下Compose中的movableContentWithReceiverOf,在Jetpack Compose开发中movableContentWithReceiverOf是用于创建可移动的组合内容的API,其核心作用是通过保留组合状态,实现将一段Composable内容封装为可在不同组合节点间“移动”的对象,避免重复重组和重新布局,提升性能。简单总结:

API:
MovableContent:可移动内容的核心类型,是封装后的Composable内容句柄
movableContentWithReceiverOf:创建带“接收者(Receiver)”的可移动内容,接收者可传递上下文数据

栗子:

import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.movableContentWithReceiverOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp data class ContentReceiver( val title: String, val color: Color, val count: Int ) @Composable fun MovableContentWithReceiverDemo() { var count by remember { mutableStateOf(0) } var isRed by remember { mutableStateOf(false) } val movableContent = remember { movableContentWithReceiverOf<ContentReceiver> { Box( modifier = Modifier .size(200.dp) .background(this.color.copy(alpha = 0.6f)) .padding(16.dp), contentAlignment = androidx.compose.ui.Alignment.Center ) { Column(horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally) { Text(text = this@movableContentWithReceiverOf.title, color = Color.White, fontSize = 18.sp) Text(text = "计数:${this@movableContentWithReceiverOf.count}", color = Color.White, fontSize = 14.sp) } } } } val receiver = ContentReceiver( title = "带接收者的可复用内容", color = if (isRed) Color.Red else Color.Green, count = count ) Column(modifier = Modifier.padding(16.dp)) { movableContent(receiver) Button( onClick = { count++ }, modifier = Modifier.padding(top = 16.dp) ) { Text(text = "增加计数") } Button( onClick = { isRed = !isRed }, modifier = Modifier.padding(top = 8.dp) ) { Text(text = "切换颜色") } } }
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.ExperimentalComposeApi import androidx.compose.runtime.InternalComposeApi import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.runtime.movableContentWithReceiverOf data class CardReceiver( val cardId: Int, val title: String, val desc: String, val bgColor: Color, val isSelected: Boolean ) @OptIn(ExperimentalComposeApi::class, InternalComposeApi::class) @Composable fun ReusableCardGroup() { var selectedCardId by remember { mutableStateOf(1) } var clickCount by remember { mutableStateOf(0) } val cardContent = remember { movableContentWithReceiverOf<CardReceiver> { Card( modifier = Modifier .fillMaxWidth() .padding(8.dp), shape = RoundedCornerShape(12.dp), border = if (this.isSelected) { BorderStroke(2.dp, Color.Black) } else { BorderStroke(1.dp, Color.Gray) }, colors = CardDefaults.cardColors( containerColor = this.bgColor.copy(alpha = if (this.isSelected) 0.9f else 0.7f) ), elevation = CardDefaults.cardElevation( defaultElevation = if (this.isSelected) 8.dp else 2.dp ) ) { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = this@movableContentWithReceiverOf.title, fontSize = 18.sp, fontWeight = FontWeight.Bold, color = Color.White ) Text( text = "${this@movableContentWithReceiverOf.desc} | 全局点击数:$clickCount", fontSize = 14.sp, color = Color.White.copy(alpha = 0.8f), modifier = Modifier.padding(top = 4.dp) ) Text( text = "卡片ID:${this@movableContentWithReceiverOf.cardId}", fontSize = 12.sp, color = Color.White.copy(alpha = 0.6f), modifier = Modifier.padding(top = 8.dp) ) } } } } Column( modifier = Modifier .fillMaxSize() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top ) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically ) { Button( onClick = { selectedCardId = if (selectedCardId == 1) 2 else 1 }, modifier = Modifier.padding(4.dp) ) { Text(text = "切换选中卡片") } Button( onClick = { clickCount++ }, modifier = Modifier.padding(4.dp) ) { Text(text = "点击计数+1") } } Column(modifier = Modifier.fillMaxWidth()) { val receiver1 = CardReceiver( cardId = 1, title = "用户信息卡片", desc = "姓名:张三 | 年龄:25", bgColor = Color(0xFF64B5F6), // 蓝色 isSelected = selectedCardId == 1 ) val card1 = cardContent(receiver1) val receiver2 = CardReceiver( cardId = 2, title = "订单信息卡片", desc = "订单号:20260117 | 金额:99元", bgColor = Color(0xFF81C784), // 绿色 isSelected = selectedCardId == 2 ) cardContent(receiver2) } } } @Composable fun MovableContentDemoApp() { Column(modifier = Modifier.fillMaxSize()) { Text( text = "movableContentWithReceiverOf Demo", fontSize = 20.sp, fontWeight = FontWeight.Bold, modifier = Modifier .align(Alignment.CenterHorizontally) .padding(16.dp) ) ReusableCardGroup() } }

注意:
1 必须配合remember使用:movableContentWithReceiverOf需在remember块内调用,以确保组合内容在重新组合时不会被回收。
2 接收者类型需明确 指定正确的接收者类型,否则无法访问布局相关的上下文。
3 参数传递需显式 依赖项应通过参数传入。

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

HeyGem系统使用技巧:提升AI口型同步质量的5个要点

HeyGem系统使用技巧&#xff1a;提升AI口型同步质量的5个要点 在AI数字人视频生成领域&#xff0c;口型同步&#xff08;Lip-sync&#xff09;的质量直接决定了最终输出的自然度和可信度。HeyGem 数字人视频生成系统凭借其本地化部署、批量处理能力和简洁的WebUI操作界面&…

作者头像 李华
网站建设 2026/3/13 22:51:13

BAAI/bge-m3技术解析:语义空间的维度压缩

BAAI/bge-m3技术解析&#xff1a;语义空间的维度压缩 1. 引言&#xff1a;语义理解的挑战与BGE-M3的突破 在自然语言处理领域&#xff0c;如何让机器真正“理解”人类语言的含义&#xff0c;一直是核心挑战之一。传统的关键词匹配或TF-IDF等方法难以捕捉文本之间的深层语义关…

作者头像 李华
网站建设 2026/3/14 13:46:03

GPEN模型版本回滚:异常更新后的恢复操作指南

GPEN模型版本回滚&#xff1a;异常更新后的恢复操作指南 在使用GPEN人像修复增强模型进行图像处理的过程中&#xff0c;开发者或研究人员可能会因误操作、依赖冲突或非预期的代码更新导致环境异常。尤其是在多任务协作或持续集成场景下&#xff0c;模型推理性能下降、依赖库不…

作者头像 李华
网站建设 2026/3/13 14:50:21

GPEN推理结果保存在哪?输出路径与命名规则详解

GPEN推理结果保存在哪&#xff1f;输出路径与命名规则详解 1. 镜像环境说明 本镜像基于 GPEN人像修复增强模型 构建&#xff0c;预装了完整的深度学习开发环境&#xff0c;集成了推理及评估所需的所有依赖&#xff0c;开箱即用。用户无需手动配置复杂的运行时依赖或下载模型权…

作者头像 李华
网站建设 2026/3/14 9:44:37

CAM++实操手册:单文件与批量提取Embedding技巧

CAM实操手册&#xff1a;单文件与批量提取Embedding技巧 1. 章节名称 CAM 是一个基于深度学习的说话人识别系统&#xff0c;由科哥开发并进行 WebUI 二次封装&#xff0c;旨在提供高效、准确的语音特征提取与说话人验证能力。该系统依托于达摩院开源的 speech_campplus_sv_zh…

作者头像 李华
网站建设 2026/3/15 20:21:42

语音识别技术实践|科哥定制FunASR镜像助力高精度中文转录

语音识别技术实践&#xff5c;科哥定制FunASR镜像助力高精度中文转录 1. 引言&#xff1a;高精度中文语音识别的工程挑战 随着智能语音交互场景的不断扩展&#xff0c;对高精度、低延迟的中文语音识别系统需求日益增长。尽管开源社区已有多个成熟的ASR&#xff08;Automatic …

作者头像 李华