<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Resmic's | BLOG</title><link>https://blog.resmic.cn/</link><description>个人博客</description><item><title>PHP 8.4 新特性全解析：属性钩子、懒对象与不对称可见性实战指南</title><link>https://blog.resmic.cn/post/347.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260807080346178606102676411.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;PHP 8.4 概览：为什么这次升级值得关注&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，是 PHP 8.x 系列中变化最为显著的一个版本。与前几个版本侧重于性能优化不同，8.4 带来了大量语言层面的语法糖与新特性，让 PHP 代码更简洁、更类型安全，同时也更接近现代语言的表达能力。&lt;/p&gt;&lt;p&gt;本文将逐一深入介绍 PHP 8.4 的核心特性，并提供真实可用的代码示例，帮助你快速上手。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;属性钩子（Property Hooks）—— 告别冗余的 getter/setter&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;懒对象（Lazy Objects）—— 延迟初始化的优雅实现&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;不对称可见性（Asymmetric Visibility）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;new 无需括号加链式调用改进&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;全局 JIT 增强与性能提升&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增数组、字符串函数&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;废弃与移除项梳理&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;属性钩子（Property Hooks）：彻底革新访问器写法&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 最受期待的特性之一，灵感来自 C# 和 Kotlin。它允许你在属性定义处直接内嵌 get 和 set 逻辑，无需手动定义独立的 getter/setter 方法。&lt;/p&gt;&lt;p&gt;以一个典型的用户全名拼接场景为例：定义一个 fullName 属性，其 get 钩子自动将 firstName 和 lastName 拼接，set 钩子则自动将全名拆分到两个属性中。这样调用方只需要操作 fullName 这一个属性，内部逻辑完全封装。&lt;/p&gt;&lt;p&gt;属性钩子的优势在于：代码更内聚，属性定义与逻辑在同一位置；接口中可以声明带钩子的属性（只声明 get，不声明 set 即为只读）；与类型声明完全兼容；只读属性（readonly）可与 get 钩子组合使用。&lt;/p&gt;&lt;h2&gt;懒对象（Lazy Objects）：按需初始化的利器&lt;/h2&gt;&lt;p&gt;PHP 8.4 引入了原生懒对象支持，通过 ReflectionClass 的新方法来创建代理或幽灵对象，仅在首次访问时才触发真正的初始化逻辑。这在依赖注入容器、ORM 延迟加载等场景中极为有用。&lt;/p&gt;&lt;p&gt;懒对象有两种模式：Ghost Object（幽灵对象）——初始化器直接修改对象本身，无中间代理层，性能最优；Virtual Proxy（虚代理）——由初始化器返回一个真实实例，代理将所有操作转发给它。在实际项目中，Ghost 模式更适合已知类型的延迟构造，Proxy 模式则适合需要替换底层实现的场景。&lt;/p&gt;&lt;h2&gt;不对称可见性（Asymmetric Visibility）&lt;/h2&gt;&lt;p&gt;在 PHP 8.4 之前，属性的读写可见性必须相同（或使用 readonly）。8.4 新增了不对称可见性语法，允许分别为读和写指定不同的访问级别。&lt;/p&gt;&lt;p&gt;典型用法是 public private(set)——外部代码可以读取该属性，但只有类内部才能修改它。这一特性结合了 readonly 的安全性与普通属性的灵活性，特别适合领域模型（Domain Model）的设计：对外暴露读接口，对内保留写控制。&lt;/p&gt;&lt;h2&gt;new 表达式无需括号与新增实用函数&lt;/h2&gt;&lt;p&gt;PHP 8.4 允许在 new 表达式后直接链式调用方法或访问属性，无需额外的括号包裹。虽然是小改动，但在流式 API 设计中能让代码更加简洁易读，减少一层括号嵌套带来的视觉噪音。&lt;/p&gt;&lt;p&gt;同时，PHP 8.4 新增了若干开发者呼声较高的内置函数：array_find 和 array_find_key 用于查找第一个满足条件的元素或键；array_all 和 array_any 替代了以往需要 array_filter 才能完成的全量/任意判断；mb_trim、mb_ltrim、mb_rtrim 提供多字节安全的字符串修剪，正确处理中文全角空格等场景。&lt;/p&gt;&lt;h2&gt;JIT 编译器增强与性能数据&lt;/h2&gt;&lt;p&gt;PHP 8.4 对 JIT（Just-In-Time）编译器进行了重要改进，主要体现在：ARM64 架构优化，Apple Silicon 和 AWS Graviton 服务器性能提升明显；循环优化，紧密循环的执行效率提升约 10-15%；更好的 opcache 协作，减少重新编译开销。&lt;/p&gt;&lt;p&gt;官方基准测试（Symfony Demo）显示，PHP 8.4 相比 8.3 有约 5-8% 的整体性能提升，在计算密集型任务中提升更为显著。&lt;/p&gt;&lt;h2&gt;升级指南与总结&lt;/h2&gt;&lt;p&gt;在升级到 PHP 8.4 时，需要关注以下废弃项：E_STRICT 常量被废弃；隐式将 null 传递给不可为 null 参数会产生弃用警告（将在 PHP 9 中成为错误）；部分 LDAP 函数参数顺序调整。&lt;/p&gt;&lt;p&gt;PHP 8.4 是一次真正意义上的语言进化，属性钩子、懒对象、不对称可见性等特性不只是语法糖，而是从根本上改变了我们设计类与对象的方式。配合 JIT 性能提升和一批实用的新函数，这次升级的综合收益非常高。建议在测试环境用 Docker 率先体验，逐步将新特性引入代码库，享受现代 PHP 带来的开发效率提升。&lt;/p&gt;</description><pubDate>Fri, 07 Aug 2026 08:09:32 +0800</pubDate></item><item><title>Jetpack Compose 性能优化实战：重组机制与状态管理最佳实践</title><link>https://blog.resmic.cn/post/346.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260806080229178597454958536.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;一、为什么选择 Jetpack Compose？&lt;/h2&gt;&lt;p&gt;自 2021 年正式发布以来，Jetpack Compose 已经从&amp;quot;值得尝试&amp;quot;演变为 Android 官方推荐的 UI 开发框架。相比传统的 XML 布局方式，Compose 带来了声明式 UI、更简洁的代码结构和更强的可复用性。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;声明式编程模型&lt;/strong&gt;：UI 是状态的函数，状态变化自动触发重组&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;无 XML 文件&lt;/strong&gt;：全部用 Kotlin 编写，告别繁琐的视图绑定&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;与 Material Design 3 深度集成&lt;/strong&gt;：主题系统更灵活，组件更现代&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;更好的预览支持&lt;/strong&gt;：Android Studio 实时预览大幅提升开发效率&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;但 Compose 并非没有学习曲线。理解其核心机制——重组（Recomposition）——是写出高性能 Compose 代码的关键。&lt;/p&gt;&lt;h2&gt;二、深入理解重组机制&lt;/h2&gt;&lt;p&gt;重组是 Compose 更新 UI 的核心方式。当 Composable 函数依赖的 State 发生变化时，该函数及其子函数会重新执行。理解重组的触发条件和范围，可以帮助我们避免不必要的性能损耗。&lt;/p&gt;&lt;p&gt;Compose 使用&lt;strong&gt;智能重组&lt;/strong&gt;策略：只有依赖了变化状态的 Composable 才会重组，未受影响的部分会被跳过。这依赖于参数的&amp;quot;稳定性&amp;quot;判断。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;不推荐：每次父组件重组，List&amp;nbsp;都被视为不稳定，导致子组件无法跳过重组
@Composable
fun&amp;nbsp;UserList(users:&amp;nbsp;List&amp;lt;User&amp;gt;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;users.forEach&amp;nbsp;{&amp;nbsp;UserItem(it)&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;推荐：用&amp;nbsp;ImmutableList&amp;nbsp;标记为稳定，Compose&amp;nbsp;可以智能跳过
@Composable
fun&amp;nbsp;UserList(users:&amp;nbsp;ImmutableList&amp;lt;User&amp;gt;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;users.forEach&amp;nbsp;{&amp;nbsp;UserItem(it)&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;可以通过 Android Studio 的 &lt;strong&gt;Compose Compiler Metrics&lt;/strong&gt; 插件查看各 Composable 的稳定性报告，找出频繁重组的元凶。&lt;/p&gt;&lt;h2&gt;三、关键性能优化技巧&lt;/h2&gt;&lt;p&gt;掌握以下几个核心优化手段，可以显著提升 Compose 应用的流畅度。&lt;/p&gt;&lt;h3&gt;1. remember 与 derivedStateOf&lt;/h3&gt;&lt;p&gt;使用 &lt;code&gt;remember&lt;/code&gt; 缓存计算结果，避免每次重组都重新计算。对于从多个 State 派生的值，优先用 &lt;code&gt;derivedStateOf&lt;/code&gt;：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;仅在&amp;nbsp;items&amp;nbsp;或&amp;nbsp;filter&amp;nbsp;变化时才重新计算，避免无关重组触发计算
val&amp;nbsp;filteredItems&amp;nbsp;by&amp;nbsp;remember(items,&amp;nbsp;filter)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;derivedStateOf&amp;nbsp;{&amp;nbsp;items.filter&amp;nbsp;{&amp;nbsp;it.name.contains(filter)&amp;nbsp;}&amp;nbsp;}
}&lt;/pre&gt;&lt;h3&gt;2. 拆分读取与写入 State 的 Composable&lt;/h3&gt;&lt;p&gt;将&amp;quot;读取状态&amp;quot;和&amp;quot;使用状态&amp;quot;的代码拆分到最小粒度的 Composable 中，让重组范围尽可能小：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;整个组件都会因&amp;nbsp;scrollOffset&amp;nbsp;变化而重组
@Composable
fun&amp;nbsp;Header(scrollState:&amp;nbsp;ScrollState,&amp;nbsp;title:&amp;nbsp;String)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;offset&amp;nbsp;=&amp;nbsp;scrollState.value
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Box(modifier&amp;nbsp;=&amp;nbsp;Modifier.offset(y&amp;nbsp;=&amp;nbsp;(-offset).dp))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(title)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;只有&amp;nbsp;AnimatedHeader&amp;nbsp;因&amp;nbsp;scrollOffset&amp;nbsp;变化而重组，Title&amp;nbsp;不受影响
@Composable
fun&amp;nbsp;Header(scrollState:&amp;nbsp;ScrollState,&amp;nbsp;title:&amp;nbsp;String)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedHeader(scrollState)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TitleText(title)
}&lt;/pre&gt;&lt;h3&gt;3. LazyColumn 的 key 参数&lt;/h3&gt;&lt;pre&gt;LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;userList,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;{&amp;nbsp;user&amp;nbsp;-&amp;gt;&amp;nbsp;user.id&amp;nbsp;}&amp;nbsp;&amp;nbsp;//&amp;nbsp;提供稳定&amp;nbsp;key，避免整体重组
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;user&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UserItem(user)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;四、状态管理最佳实践&lt;/h2&gt;&lt;p&gt;良好的状态管理架构是大型 Compose 项目稳健运行的基础。推荐结合 &lt;strong&gt;ViewModel + UiState&lt;/strong&gt; 模式：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;UiState&amp;nbsp;数据类：所有&amp;nbsp;UI&amp;nbsp;状态集中管理
data&amp;nbsp;class&amp;nbsp;UserListUiState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;users:&amp;nbsp;ImmutableList&amp;lt;User&amp;gt;&amp;nbsp;=&amp;nbsp;persistentListOf(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;isLoading:&amp;nbsp;Boolean&amp;nbsp;=&amp;nbsp;false,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;errorMessage:&amp;nbsp;String?&amp;nbsp;=&amp;nbsp;null
)

class&amp;nbsp;UserListViewModel&amp;nbsp;:&amp;nbsp;ViewModel()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;val&amp;nbsp;_uiState&amp;nbsp;=&amp;nbsp;MutableStateFlow(UserListUiState())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;uiState:&amp;nbsp;StateFlow&amp;lt;UserListUiState&amp;gt;&amp;nbsp;=&amp;nbsp;_uiState.asStateFlow()

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fun&amp;nbsp;loadUsers()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;viewModelScope.launch&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_uiState.update&amp;nbsp;{&amp;nbsp;it.copy(isLoading&amp;nbsp;=&amp;nbsp;true)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;users&amp;nbsp;=&amp;nbsp;repository.getUsers()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_uiState.update&amp;nbsp;{&amp;nbsp;it.copy(users&amp;nbsp;=&amp;nbsp;users.toImmutableList(),&amp;nbsp;isLoading&amp;nbsp;=&amp;nbsp;false)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(e:&amp;nbsp;Exception)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_uiState.update&amp;nbsp;{&amp;nbsp;it.copy(errorMessage&amp;nbsp;=&amp;nbsp;e.message,&amp;nbsp;isLoading&amp;nbsp;=&amp;nbsp;false)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;在 Composable 中用 &lt;code&gt;collectAsStateWithLifecycle()&lt;/code&gt; 收集（而非 &lt;code&gt;collectAsState()&lt;/code&gt;），以遵循 Lifecycle 感知最佳实践，避免后台不必要的更新。&lt;/p&gt;&lt;h2&gt;五、实战建议与常见坑&lt;/h2&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;避免在 Composable 中直接创建 ViewModel 实例&lt;/strong&gt;，应通过 &lt;code&gt;viewModel()&lt;/code&gt; 或 Hilt 注入&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;慎用 SideEffect 系列 API&lt;/strong&gt;（LaunchedEffect/DisposableEffect），确保 key 设置正确，防止重复执行&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;图片加载用 Coil&lt;/strong&gt;：Coil 3 已原生支持 Compose，&lt;code&gt;AsyncImage&lt;/code&gt; 开箱即用&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;避免在 Column/Row 中放大量固定 item&lt;/strong&gt;：超过屏幕内容请改用 LazyColumn/LazyRow&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;测量性能时用 Release 包&lt;/strong&gt;：Debug 模式下 Compose 额外开销较大，数据不准确&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Jetpack Compose 的性能上限很高，但需要开发者主动理解其工作原理并遵循最佳实践。建议在项目中逐步引入 Compose Compiler Metrics 和 Compose 布局检查器，持续发现和解决性能问题。随着 Compose 生态的不断成熟，它将成为每个 Android 开发者的必备技能。&lt;/p&gt;</description><pubDate>Thu, 06 Aug 2026 08:07:31 +0800</pubDate></item><item><title>RAG技术深度指南：用检索增强生成构建高精度企业知识库</title><link>https://blog.resmic.cn/post/345.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260805080409178588824991560.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;RAG 技术概述：为什么 LLM 需要外挂知识库&lt;/h2&gt;&lt;p&gt;大语言模型（LLM）虽然拥有强大的自然语言理解与生成能力，但存在两个核心缺陷：知识截止日期和幻觉问题。训练数据的静态性使得 GPT-4、Claude 等模型无法感知最新信息；而参数化记忆的不稳定性，则导致模型在特定领域（如企业私有文档、法律条文、医疗规范）容易&amp;quot;一本正经地胡说八道&amp;quot;。&lt;/p&gt;&lt;p&gt;RAG（Retrieval-Augmented Generation，检索增强生成）正是解决这两个问题的工程范式。其核心思路是：在用户提问时，先从外部知识库检索相关片段，再将检索内容与问题一起送入 LLM，让模型基于真实文档进行回答，而非凭空捏造。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;减少幻觉&lt;/strong&gt;：模型答案有文档支撑，可溯源验证&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;实时更新&lt;/strong&gt;：更新向量库即可让模型&amp;quot;学会&amp;quot;最新知识，无需重新训练&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;成本可控&lt;/strong&gt;：相比全量微调，RAG 构建和维护成本极低&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;隐私安全&lt;/strong&gt;：企业数据无需上传至 LLM 训练集&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;RAG 的三代演进：从朴素检索到模块化架构&lt;/h2&gt;&lt;p&gt;RAG 技术在过去两年经历了三个明显的代际跃迁，理解这一演进路径有助于选择合适的技术方案。&lt;/p&gt;&lt;h3&gt;第一代：朴素 RAG（Naive RAG）&lt;/h3&gt;&lt;p&gt;最早期的 RAG 实现极为简单：将文档切块 → 向量化 → 存入向量数据库 → 查询时检索 Top-K → 拼接 Prompt 送入 LLM。这一范式虽然可行，但存在明显短板：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;固定 chunk size 导致语义被截断&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;纯向量相似度忽略关键词精确匹配&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;检索结果直接输入，噪声大&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;第二代：高级 RAG（Advanced RAG）&lt;/h3&gt;&lt;p&gt;高级 RAG 在检索前（Pre-Retrieval）和检索后（Post-Retrieval）各增加了优化环节。前者包括查询改写、HyDE（假设文档嵌入）；后者包括重排序（Rerank）、上下文压缩和答案融合。&lt;/p&gt;&lt;h3&gt;第三代：模块化 RAG（Modular RAG）&lt;/h3&gt;&lt;p&gt;模块化 RAG 将整个流水线拆解为可自由组合的模块：检索模块、融合模块、生成模块、记忆模块等，支持路由、迭代、自适应等复杂策略，代表框架有 LlamaIndex 的 Pipeline API 和 LangChain Expression Language（LCEL）。&lt;/p&gt;&lt;h2&gt;向量检索优化：Embedding 模型与混合检索策略&lt;/h2&gt;&lt;p&gt;向量检索是 RAG 的基石。选择合适的 Embedding 模型和检索策略，对最终效果影响巨大。&lt;/p&gt;&lt;h3&gt;Embedding 模型选择&lt;/h3&gt;&lt;p&gt;中文场景推荐使用 BAAI/bge-large-zh-v1.5 或 text2vec-large-chinese，英文场景可选 OpenAI text-embedding-3-large 或开源的 E5-large-v2。关键指标是在 MTEB 榜单上的检索任务（Retrieval）得分。&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain_community.embeddings&amp;nbsp;import&amp;nbsp;HuggingFaceEmbeddings

embeddings&amp;nbsp;=&amp;nbsp;HuggingFaceEmbeddings(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;model_name=&amp;quot;BAAI/bge-large-zh-v1.5&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;model_kwargs={&amp;quot;device&amp;quot;:&amp;nbsp;&amp;quot;cuda&amp;quot;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;encode_kwargs={
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;normalize_embeddings&amp;quot;:&amp;nbsp;True,&amp;nbsp;&amp;nbsp;#&amp;nbsp;余弦相似度必须归一化
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;batch_size&amp;quot;:&amp;nbsp;64
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
)&lt;/pre&gt;&lt;h3&gt;混合检索（Hybrid Search）&lt;/h3&gt;&lt;p&gt;单纯的向量检索在面对精确关键词（如产品型号、人名、代码函数名）时表现欠佳。混合检索结合稠密向量检索（Dense）和稀疏关键词检索（Sparse，如 BM25），通过 RRF（Reciprocal Rank Fusion）融合两路结果，显著提升召回率。&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain.retrievers&amp;nbsp;import&amp;nbsp;EnsembleRetriever
from&amp;nbsp;langchain_community.retrievers&amp;nbsp;import&amp;nbsp;BM25Retriever
from&amp;nbsp;langchain_community.vectorstores&amp;nbsp;import&amp;nbsp;Chroma

#&amp;nbsp;构建&amp;nbsp;BM25&amp;nbsp;检索器
bm25_retriever&amp;nbsp;=&amp;nbsp;BM25Retriever.from_documents(docs)
bm25_retriever.k&amp;nbsp;=&amp;nbsp;5

#&amp;nbsp;构建向量检索器
vectorstore&amp;nbsp;=&amp;nbsp;Chroma.from_documents(docs,&amp;nbsp;embeddings)
vector_retriever&amp;nbsp;=&amp;nbsp;vectorstore.as_retriever(search_kwargs={&amp;quot;k&amp;quot;:&amp;nbsp;5})

#&amp;nbsp;混合检索，权重&amp;nbsp;4:6
ensemble_retriever&amp;nbsp;=&amp;nbsp;EnsembleRetriever(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retrievers=[bm25_retriever,&amp;nbsp;vector_retriever],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;weights=[0.4,&amp;nbsp;0.6]
)
results&amp;nbsp;=&amp;nbsp;ensemble_retriever.get_relevant_documents(&amp;quot;如何配置负载均衡？&amp;quot;)&lt;/pre&gt;&lt;h2&gt;重排序与上下文压缩：让 LLM 只看最关键的内容&lt;/h2&gt;&lt;p&gt;检索到的 Top-K 文档片段质量参差不齐，直接塞入 Prompt 会引入大量噪声，还可能超出上下文窗口。重排序（Rerank）和上下文压缩是两个关键的 Post-Retrieval 优化手段。&lt;/p&gt;&lt;h3&gt;Cross-Encoder 重排序&lt;/h3&gt;&lt;p&gt;Bi-Encoder（即普通 Embedding 模型）对 Query 和文档分别编码，速度快但精度有损。Cross-Encoder 将 Query+文档一起输入，联合计算相关性得分，精度更高，适合作为精排阶段。&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain.retrievers.document_compressors&amp;nbsp;import&amp;nbsp;CrossEncoderReranker
from&amp;nbsp;langchain_community.cross_encoders&amp;nbsp;import&amp;nbsp;HuggingFaceCrossEncoder
from&amp;nbsp;langchain.retrievers&amp;nbsp;import&amp;nbsp;ContextualCompressionRetriever

#&amp;nbsp;使用&amp;nbsp;BGE&amp;nbsp;Reranker
reranker_model&amp;nbsp;=&amp;nbsp;HuggingFaceCrossEncoder(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;model_name=&amp;quot;BAAI/bge-reranker-large&amp;quot;
)
compressor&amp;nbsp;=&amp;nbsp;CrossEncoderReranker(model=reranker_model,&amp;nbsp;top_n=3)

compression_retriever&amp;nbsp;=&amp;nbsp;ContextualCompressionRetriever(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_compressor=compressor,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_retriever=ensemble_retriever
)&lt;/pre&gt;&lt;h3&gt;LLM 上下文压缩&lt;/h3&gt;&lt;p&gt;使用轻量级 LLM 对检索片段进行摘要或抽取，只保留与问题直接相关的句子，大幅压缩 Prompt 长度：&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain.retrievers.document_compressors&amp;nbsp;import&amp;nbsp;LLMChainExtractor
from&amp;nbsp;langchain_openai&amp;nbsp;import&amp;nbsp;ChatOpenAI

llm&amp;nbsp;=&amp;nbsp;ChatOpenAI(model=&amp;quot;gpt-4o-mini&amp;quot;,&amp;nbsp;temperature=0)
extractor&amp;nbsp;=&amp;nbsp;LLMChainExtractor.from_llm(llm)

compression_retriever&amp;nbsp;=&amp;nbsp;ContextualCompressionRetriever(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_compressor=extractor,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_retriever=ensemble_retriever
)&lt;/pre&gt;&lt;h2&gt;查询改写与 HyDE：提升检索召回率的前处理技巧&lt;/h2&gt;&lt;p&gt;用户的原始问题往往过于简短或表述模糊，与知识库中的文档措辞不一致，导致向量相似度偏低。查询改写和 HyDE 是两种常用的 Pre-Retrieval 优化策略。&lt;/p&gt;&lt;h3&gt;多查询扩展（Multi-Query）&lt;/h3&gt;&lt;p&gt;让 LLM 将一个问题改写为多个不同角度的问题，分别检索后合并去重，增大召回面：&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain.retrievers.multi_query&amp;nbsp;import&amp;nbsp;MultiQueryRetriever

multi_query_retriever&amp;nbsp;=&amp;nbsp;MultiQueryRetriever.from_llm(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retriever=ensemble_retriever,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;llm=ChatOpenAI(model=&amp;quot;gpt-4o-mini&amp;quot;)
)
#&amp;nbsp;自动生成3个变体问题并合并结果
docs&amp;nbsp;=&amp;nbsp;multi_query_retriever.get_relevant_documents(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;RAG系统如何避免幻觉？&amp;quot;
)&lt;/pre&gt;&lt;h3&gt;HyDE（Hypothetical Document Embeddings）&lt;/h3&gt;&lt;p&gt;先让 LLM 根据问题生成一段&amp;quot;假设答案&amp;quot;，再用假设答案的向量去检索知识库，因为假设答案与真实文档的语义更接近，检索效果往往优于直接用问题向量：&lt;/p&gt;&lt;pre&gt;from&amp;nbsp;langchain.chains&amp;nbsp;import&amp;nbsp;HypotheticalDocumentEmbedder

hyde_embeddings&amp;nbsp;=&amp;nbsp;HypotheticalDocumentEmbedder.from_llm(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;llm=ChatOpenAI(model=&amp;quot;gpt-4o-mini&amp;quot;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_embeddings=embeddings,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;custom_prompt=&amp;quot;&amp;quot;&amp;quot;请用中文写一段100字左右的文档片段，用于回答以下问题：
{QUESTION}
文档片段：&amp;quot;&amp;quot;&amp;quot;
)
vectorstore_hyde&amp;nbsp;=&amp;nbsp;Chroma.from_documents(docs,&amp;nbsp;hyde_embeddings)&lt;/pre&gt;&lt;h2&gt;完整企业级 RAG Pipeline 实战：以内部知识库问答为例&lt;/h2&gt;&lt;p&gt;下面展示一个完整的企业级 RAG 系统搭建流程，涵盖文档加载、切块、建库、检索、生成各环节，可直接用于生产环境。&lt;/p&gt;&lt;h3&gt;文档预处理与智能切块&lt;/h3&gt;&lt;pre&gt;from&amp;nbsp;langchain_community.document_loaders&amp;nbsp;import&amp;nbsp;PyMuPDFLoader,&amp;nbsp;DirectoryLoader
from&amp;nbsp;langchain.text_splitter&amp;nbsp;import&amp;nbsp;RecursiveCharacterTextSplitter

#&amp;nbsp;加载企业文档（支持&amp;nbsp;PDF、Word、TXT）
loader&amp;nbsp;=&amp;nbsp;DirectoryLoader(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;./docs/&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;glob=&amp;quot;**/*.pdf&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loader_cls=PyMuPDFLoader
)
raw_docs&amp;nbsp;=&amp;nbsp;loader.load()

#&amp;nbsp;中文语义感知切块：优先在段落/句子边界切分
splitter&amp;nbsp;=&amp;nbsp;RecursiveCharacterTextSplitter(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chunk_size=512,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chunk_overlap=64,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;separators=[&amp;quot;\n\n&amp;quot;,&amp;nbsp;&amp;quot;\n&amp;quot;,&amp;nbsp;&amp;quot;。&amp;quot;,&amp;nbsp;&amp;quot;！&amp;quot;,&amp;nbsp;&amp;quot;？&amp;quot;,&amp;nbsp;&amp;quot;；&amp;quot;,&amp;nbsp;&amp;quot;&amp;nbsp;&amp;quot;,&amp;nbsp;&amp;quot;&amp;quot;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;length_function=len
)
chunks&amp;nbsp;=&amp;nbsp;splitter.split_documents(raw_docs)
print(f&amp;quot;共切分为&amp;nbsp;{len(chunks)}&amp;nbsp;个文本块&amp;quot;)&lt;/pre&gt;&lt;h3&gt;构建向量存储与检索链&lt;/h3&gt;&lt;pre&gt;import&amp;nbsp;os
from&amp;nbsp;langchain_community.vectorstores&amp;nbsp;import&amp;nbsp;Chroma
from&amp;nbsp;langchain_openai&amp;nbsp;import&amp;nbsp;ChatOpenAI
from&amp;nbsp;langchain.chains&amp;nbsp;import&amp;nbsp;RetrievalQA
from&amp;nbsp;langchain.prompts&amp;nbsp;import&amp;nbsp;PromptTemplate

#&amp;nbsp;持久化向量库
vectorstore&amp;nbsp;=&amp;nbsp;Chroma.from_documents(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;documents=chunks,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;embedding=embeddings,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;persist_directory=&amp;quot;./chroma_db&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;collection_name=&amp;quot;enterprise_kb&amp;quot;
)

#&amp;nbsp;自定义&amp;nbsp;RAG&amp;nbsp;Prompt（中文）
RAG_PROMPT&amp;nbsp;=&amp;nbsp;PromptTemplate(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;input_variables=[&amp;quot;context&amp;quot;,&amp;nbsp;&amp;quot;question&amp;quot;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;template=&amp;quot;&amp;quot;&amp;quot;你是企业内部知识库助手。请严格根据以下参考文档回答问题，不要编造信息。
如果文档中没有相关信息，请明确回复&amp;quot;文档中未找到相关信息&amp;quot;。

参考文档：
{context}

问题：{question}

回答：&amp;quot;&amp;quot;&amp;quot;
)

#&amp;nbsp;组装完整&amp;nbsp;RAG&amp;nbsp;链
qa_chain&amp;nbsp;=&amp;nbsp;RetrievalQA.from_chain_type(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;llm=ChatOpenAI(model=&amp;quot;gpt-4o&amp;quot;,&amp;nbsp;temperature=0),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chain_type=&amp;quot;stuff&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retriever=compression_retriever,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return_source_documents=True,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chain_type_kwargs={&amp;quot;prompt&amp;quot;:&amp;nbsp;RAG_PROMPT}
)

#&amp;nbsp;问答示例
result&amp;nbsp;=&amp;nbsp;qa_chain.invoke({&amp;quot;query&amp;quot;:&amp;nbsp;&amp;quot;年假政策是怎样的？&amp;quot;})
print(&amp;quot;答案：&amp;quot;,&amp;nbsp;result[&amp;quot;result&amp;quot;])
print(&amp;quot;来源：&amp;quot;,&amp;nbsp;[d.metadata[&amp;quot;source&amp;quot;]&amp;nbsp;for&amp;nbsp;d&amp;nbsp;in&amp;nbsp;result[&amp;quot;source_documents&amp;quot;]])&lt;/pre&gt;&lt;h2&gt;生产部署注意事项与性能调优&lt;/h2&gt;&lt;p&gt;在实际部署 RAG 系统时，以下几个方面需要重点关注，直接影响系统的可用性和答案质量。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;向量库选型&lt;/strong&gt;：小规模（&amp;lt;100万条）用 Chroma 或 FAISS 即可；百万级以上推荐 Milvus 或 Weaviate，支持分布式和过滤检索&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;异步批量入库&lt;/strong&gt;：文档入库时使用异步 + 批量操作，避免阻塞主进程；Chroma 支持 &lt;code&gt;add_documents&lt;/code&gt; 批量写入&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;缓存层&lt;/strong&gt;：对高频重复问题启用语义缓存（LangChain 的 &lt;code&gt;RedisSemanticCache&lt;/code&gt;），可降低 70%+ LLM 调用成本&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;评估体系&lt;/strong&gt;：使用 RAGAS 框架对系统进行自动化评估，重点关注 faithfulness（忠实度）、answer_relevancy（答案相关性）和 context_precision（上下文精准度）三项指标&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;元数据过滤&lt;/strong&gt;：为文档片段添加部门、时间、权限等元数据，检索时加入过滤条件，实现细粒度的权限控制&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;流式输出&lt;/strong&gt;：生产环境启用 LLM 流式输出（&lt;code&gt;streaming=True&lt;/code&gt;），配合 SSE 或 WebSocket 推送，提升用户体验&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;RAG 技术仍在快速演进中，Graph RAG（微软）、Corrective RAG（CRAG）、Self-RAG 等变体不断涌现。掌握本文介绍的核心技术栈，你已经具备构建企业级 AI 知识库的完整能力。&lt;/p&gt;</description><pubDate>Wed, 05 Aug 2026 08:04:36 +0800</pubDate></item><item><title>Jetpack Compose 性能优化实战：彻底消除 UI 卡顿的5个关键技巧</title><link>https://blog.resmic.cn/post/344.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260804080417178580185772885.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;p&gt;Jetpack Compose 自 1.0 正式发布以来，已成为 Android UI 开发的主流选择。然而，Compose 的声明式范式与传统 View 体系截然不同，许多开发者在享受其便捷性的同时，也遭遇了莫名的性能问题：列表滑动不流畅、动画掉帧、冷启动变慢。本文将深入剖析 Compose 性能瓶颈的根本原因，并给出可落地的优化方案。&lt;/p&gt;&lt;h2&gt;一、理解重组（Recomposition）：性能问题的根源&lt;/h2&gt;&lt;p&gt;Compose 的核心机制是重组——当状态（State）发生变化时，相关的 Composable 函数会重新执行。理解重组的触发边界，是所有性能优化的前提。&lt;/p&gt;&lt;p&gt;Compose 编译器会为每个 Composable 函数插入&amp;quot;稳定性检查&amp;quot;代码。只有当传入参数发生真实变化时，该函数才会触发重组。如果参数类型被标记为&lt;strong&gt;不稳定（Unstable）&lt;/strong&gt;，Compose 无法做差异比较，每次父级重组都会强制重组子级。&lt;/p&gt;&lt;p&gt;常见的不稳定类型包括：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;、&lt;code&gt;Map&amp;lt;K,V&amp;gt;&lt;/code&gt; 等标准集合（应替换为 &lt;code&gt;ImmutableList&lt;/code&gt;）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;包含 &lt;code&gt;var&lt;/code&gt; 属性的普通 data class&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;引用了 Android Framework 类的对象（如 &lt;code&gt;Context&lt;/code&gt;、&lt;code&gt;Resources&lt;/code&gt;）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：使用 &lt;code&gt;@Stable&lt;/code&gt; 或 &lt;code&gt;@Immutable&lt;/code&gt; 注解，以及 Kotlinx Immutable Collections 库：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;使用不可变集合
implementation(&amp;quot;org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7&amp;quot;)

//&amp;nbsp;标记稳定数据类
@Immutable
data&amp;nbsp;class&amp;nbsp;UserProfile(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;id:&amp;nbsp;String,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;name:&amp;nbsp;String,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;avatarUrl:&amp;nbsp;String
)

@Composable
fun&amp;nbsp;UserCard(profile:&amp;nbsp;UserProfile)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;只有&amp;nbsp;profile&amp;nbsp;引用变化时才重组
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(text&amp;nbsp;=&amp;nbsp;profile.name)
}&lt;/pre&gt;&lt;h2&gt;二、状态下沉与 derivedStateOf：精准控制重组范围&lt;/h2&gt;&lt;p&gt;一个常见的反模式是将状态定义在组合树的顶层，导致任何微小变化都引发大面积重组。正确做法是&lt;strong&gt;将状态尽量下沉到最近的使用位置&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;另一个高频误区是直接在 Composable 中进行计算，而不使用 &lt;code&gt;derivedStateOf&lt;/code&gt;：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;错误：每次&amp;nbsp;listState&amp;nbsp;变化（即每帧滑动）都重组整个组件
val&amp;nbsp;showFab&amp;nbsp;=&amp;nbsp;listState.firstVisibleItemIndex&amp;nbsp;&amp;gt;&amp;nbsp;0

//&amp;nbsp;✅&amp;nbsp;正确：derivedStateOf&amp;nbsp;缓存计算结果，只在结果变化时才触发重组
val&amp;nbsp;showFab&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;derivedStateOf&amp;nbsp;{&amp;nbsp;listState.firstVisibleItemIndex&amp;nbsp;&amp;gt;&amp;nbsp;0&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;&lt;code&gt;derivedStateOf&lt;/code&gt; 特别适合以下场景：从列表滚动位置派生状态、从表单多个字段派生校验结果、从复杂对象派生展示文本。&lt;/p&gt;&lt;h2&gt;三、LazyList 性能优化：key 与 contentType 缺一不可&lt;/h2&gt;&lt;p&gt;LazyColumn / LazyRow 是 Compose 中最容易出现性能问题的组件。两个最重要的优化参数经常被忽视：&lt;/p&gt;&lt;pre&gt;LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;userList,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;✅&amp;nbsp;提供稳定的&amp;nbsp;key，避免&amp;nbsp;item&amp;nbsp;位置变化时重新创建组件
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;{&amp;nbsp;user&amp;nbsp;-&amp;gt;&amp;nbsp;user.id&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;✅&amp;nbsp;声明&amp;nbsp;contentType，让&amp;nbsp;Compose&amp;nbsp;复用相同类型的组件
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentType&amp;nbsp;=&amp;nbsp;{&amp;nbsp;user&amp;nbsp;-&amp;gt;&amp;nbsp;if&amp;nbsp;(user.isVip)&amp;nbsp;&amp;quot;vip&amp;quot;&amp;nbsp;else&amp;nbsp;&amp;quot;normal&amp;quot;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;user&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UserListItem(user&amp;nbsp;=&amp;nbsp;user)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;此外，避免在 &lt;code&gt;items&lt;/code&gt; 的 lambda 中直接传递复杂对象引用。如果 item 数据包含不稳定类型，可以只传递 ID，在子 Composable 内部通过 ViewModel 查询：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;推荐模式：只传&amp;nbsp;ID，内部查询
@Composable
fun&amp;nbsp;UserListItem(userId:&amp;nbsp;String,&amp;nbsp;viewModel:&amp;nbsp;UserViewModel&amp;nbsp;=&amp;nbsp;hiltViewModel())&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;user&amp;nbsp;by&amp;nbsp;viewModel.getUser(userId).collectAsStateWithLifecycle()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;...
}&lt;/pre&gt;&lt;h2&gt;四、使用 Layout Inspector 和 Compose 指标诊断问题&lt;/h2&gt;&lt;p&gt;优化前必须先量化问题。Android Studio 提供了强大的 Compose 专用工具链：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. Recomposition Counter（重组计数器）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在 Layout Inspector 中开启 &amp;quot;Show recomposition counts&amp;quot;，可以直观看到每个 Composable 的重组次数和跳过次数。高重组次数 + 低跳过次数 = 优化重点。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. Compose 编译器指标&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在 &lt;code&gt;build.gradle&lt;/code&gt; 中开启编译器指标输出：&lt;/p&gt;&lt;pre&gt;android&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;kotlinOptions&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;freeCompilerArgs&amp;nbsp;+=&amp;nbsp;listOf(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;-P&amp;quot;,&amp;nbsp;&amp;quot;plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=$projectDir/compose_metrics&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;-P&amp;quot;,&amp;nbsp;&amp;quot;plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=$projectDir/compose_metrics&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;编译后查看 &lt;code&gt;compose_metrics&lt;/code&gt; 目录下的报告，找出所有被标记为 &lt;code&gt;unstable&lt;/code&gt; 的类和 &lt;code&gt;restartable but not skippable&lt;/code&gt; 的函数。&lt;/p&gt;&lt;h2&gt;五、实战清单：快速提升 Compose 应用性能&lt;/h2&gt;&lt;p&gt;将以下检查项加入 Code Review 流程，可系统性地避免 Compose 性能退化：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;✅ 所有传入 Composable 的数据类均已标注 &lt;code&gt;@Immutable&lt;/code&gt; 或 &lt;code&gt;@Stable&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 集合类型使用 &lt;code&gt;ImmutableList&lt;/code&gt; / &lt;code&gt;ImmutableMap&lt;/code&gt; 替代标准集合&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ LazyList 的 &lt;code&gt;items&lt;/code&gt; 均提供了稳定的 &lt;code&gt;key&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 从滚动状态、多字段派生的布尔值均使用 &lt;code&gt;derivedStateOf&lt;/code&gt; 包裹&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 高频变化的状态（如动画值）不放在 ViewModel 的 StateFlow 中，改用 &lt;code&gt;Animatable&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 图片加载使用 Coil 3.x，并配置合理的内存缓存大小&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 避免在 Composable 函数体内创建 lambda 对象（使用 &lt;code&gt;remember&lt;/code&gt; 缓存回调）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 开启 Baseline Profile，减少 JIT 编译对首帧渲染的影响&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Compose 性能优化不是一蹴而就的工作，而是需要将正确的编码习惯内化为日常开发规范。掌握重组机制、善用工具链、建立 Review 清单，你的 Compose 应用将获得质的飞跃。&lt;/p&gt;</description><pubDate>Tue, 04 Aug 2026 08:04:36 +0800</pubDate></item><item><title>大模型推理提速利器：KV Cache 工作原理与生产级优化实践</title><link>https://blog.resmic.cn/post/343.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260803080934178571577489182.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;一、什么是 KV Cache？为什么它如此重要&lt;/h2&gt;&lt;p&gt;在大型语言模型（LLM）的推理过程中，每次生成一个新 token，模型都需要对之前所有 token 的 Key 和 Value 向量重新计算一遍——这是 Transformer 注意力机制的本质。随着上下文长度增长，这种重复计算会导致推理延迟呈二次方增长，成为生产部署中最主要的性能瓶颈。&lt;/p&gt;&lt;p&gt;KV Cache（Key-Value 缓存）的核心思想是：&lt;strong&gt;将已计算的 Key/Value 向量缓存起来，避免重复计算&lt;/strong&gt;。在自回归生成时，只需对新增 token 做一次前向计算，已有的缓存直接复用。这一优化可将推理吞吐量提升 5~20 倍，是当前所有主流推理框架的标配能力。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;GPT-4、Claude、Llama 等模型均依赖 KV Cache 实现高效推理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;没有 KV Cache，长对话场景几乎不可能做到实时响应&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;KV Cache 的内存占用与序列长度、层数、注意力头数正相关&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;二、KV Cache 的内存压力与挑战&lt;/h2&gt;&lt;p&gt;KV Cache 虽然大幅降低了计算量，但随之带来了严峻的内存挑战。以 LLaMA-2 70B 为例，在 FP16 精度下，每个 token 的 KV Cache 大小约为 1.6MB，对于 4096 token 的上下文，单条请求就需要约 6.5GB 显存。在高并发场景下，这一数字会成倍放大。&lt;/p&gt;&lt;p&gt;传统的静态预分配方式存在严重的内存碎片问题：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;内存碎片：&lt;/strong&gt;为每条请求预分配最大长度的连续内存块，实际利用率往往低于 30%&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;并发受限：&lt;/strong&gt;显存耗尽后新请求只能排队等待，GPU 利用率下降&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;批处理困难：&lt;/strong&gt;不同长度的请求难以高效地组成动态 batch&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;#&amp;nbsp;简化示意：传统静态&amp;nbsp;KV&amp;nbsp;Cache&amp;nbsp;分配
class&amp;nbsp;StaticKVCache:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;max_batch,&amp;nbsp;max_seq_len,&amp;nbsp;num_heads,&amp;nbsp;head_dim):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;为所有请求预分配固定大小的缓存块
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cache_k&amp;nbsp;=&amp;nbsp;torch.zeros(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_batch,&amp;nbsp;max_seq_len,&amp;nbsp;num_heads,&amp;nbsp;head_dim
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;).cuda()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cache_v&amp;nbsp;=&amp;nbsp;torch.zeros(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_batch,&amp;nbsp;max_seq_len,&amp;nbsp;num_heads,&amp;nbsp;head_dim
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;).cuda()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;内存浪费：大多数序列远短于&amp;nbsp;max_seq_len&lt;/pre&gt;&lt;h2&gt;三、分页注意力（PagedAttention）：虚拟内存思想的迁移&lt;/h2&gt;&lt;p&gt;vLLM 团队在 2023 年提出的 &lt;strong&gt;PagedAttention&lt;/strong&gt; 是 KV Cache 管理的革命性突破，其核心思路直接借鉴了操作系统的虚拟内存与分页机制。&lt;/p&gt;&lt;p&gt;PagedAttention 将 KV Cache 切分为固定大小的&amp;quot;块&amp;quot;（Block），每个块存储固定数量（通常16个）的 token 的 KV 向量。系统维护一张块表（Block Table），记录每条请求的 KV 数据分散存储在哪些物理块中，类似 OS 的页表。&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;PagedAttention&amp;nbsp;伪代码示意
class&amp;nbsp;PagedKVCache:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;block_size=16,&amp;nbsp;num_blocks=1000):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.block_size&amp;nbsp;=&amp;nbsp;block_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;物理块池：所有请求共享
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.physical_blocks&amp;nbsp;=&amp;nbsp;torch.zeros(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num_blocks,&amp;nbsp;2,&amp;nbsp;block_size,&amp;nbsp;num_heads,&amp;nbsp;head_dim
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;).cuda()&amp;nbsp;&amp;nbsp;#&amp;nbsp;[num_blocks,&amp;nbsp;k_or_v,&amp;nbsp;block_size,&amp;nbsp;...]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.free_blocks&amp;nbsp;=&amp;nbsp;list(range(num_blocks))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;每条请求的块表映射
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.block_table&amp;nbsp;=&amp;nbsp;{}&amp;nbsp;&amp;nbsp;#&amp;nbsp;request_id&amp;nbsp;-&amp;gt;&amp;nbsp;[block_ids]

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;allocate(self,&amp;nbsp;request_id,&amp;nbsp;num_tokens):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num_blocks&amp;nbsp;=&amp;nbsp;(num_tokens&amp;nbsp;+&amp;nbsp;self.block_size&amp;nbsp;-&amp;nbsp;1)&amp;nbsp;//&amp;nbsp;self.block_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;blocks&amp;nbsp;=&amp;nbsp;[self.free_blocks.pop()&amp;nbsp;for&amp;nbsp;_&amp;nbsp;in&amp;nbsp;range(num_blocks)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.block_table[request_id]&amp;nbsp;=&amp;nbsp;blocks
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;blocks

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;free(self,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;request_id&amp;nbsp;in&amp;nbsp;self.block_table:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.free_blocks.extend(self.block_table.pop(request_id))&lt;/pre&gt;&lt;p&gt;PagedAttention 的优势在于：内存利用率从传统方式的 ~30% 提升到 ~90%+，并且支持跨请求的 KV 块共享（Prefix Sharing），对于系统提示词（System Prompt）相同的大批量请求，可以极大减少重复存储。&lt;/p&gt;&lt;h2&gt;四、量化 KV Cache：用精度换空间&lt;/h2&gt;&lt;p&gt;除了分页管理，对 KV Cache 本身进行量化也是降低内存的主流方案。研究表明，Key 和 Value 的数值分布存在一定规律，可以在较低精度下保持大部分精度。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;FP16 → INT8：&lt;/strong&gt;内存减半，对大多数任务精度损失可忽略不计&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;FP16 → INT4：&lt;/strong&gt;内存降至 1/4，需要更精细的量化策略（如分组量化）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;KVQuant：&lt;/strong&gt;针对 KV Cache 的专用量化框架，支持 2bit 量化并维持合理精度&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;import&amp;nbsp;torch

def&amp;nbsp;quantize_kv_int8(kv_tensor):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;简单的逐通道&amp;nbsp;INT8&amp;nbsp;量化示例&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;kv_tensor&amp;nbsp;shape:&amp;nbsp;[seq_len,&amp;nbsp;num_heads,&amp;nbsp;head_dim]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_val&amp;nbsp;=&amp;nbsp;kv_tensor.abs().max(dim=-1,&amp;nbsp;keepdim=True).values
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scale&amp;nbsp;=&amp;nbsp;max_val&amp;nbsp;/&amp;nbsp;127.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scale&amp;nbsp;=&amp;nbsp;scale.clamp(min=1e-8)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;quantized&amp;nbsp;=&amp;nbsp;(kv_tensor&amp;nbsp;/&amp;nbsp;scale).round().clamp(-128,&amp;nbsp;127).to(torch.int8)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;quantized,&amp;nbsp;scale

def&amp;nbsp;dequantize_kv_int8(quantized,&amp;nbsp;scale):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;反量化&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;quantized.to(torch.float16)&amp;nbsp;*&amp;nbsp;scale&lt;/pre&gt;&lt;p&gt;在 vLLM、TensorRT-LLM 等框架中，INT8 KV Cache 量化已作为生产级特性提供，只需在配置中启用即可：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;vLLM&amp;nbsp;启动时启用&amp;nbsp;INT8&amp;nbsp;KV&amp;nbsp;Cache&amp;nbsp;量化
python&amp;nbsp;-m&amp;nbsp;vllm.entrypoints.openai.api_server&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--model&amp;nbsp;meta-llama/Llama-2-70b-chat-hf&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--kv-cache-dtype&amp;nbsp;fp8&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--max-model-len&amp;nbsp;4096&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--gpu-memory-utilization&amp;nbsp;0.9&lt;/pre&gt;&lt;h2&gt;五、生产实践：选择合适的优化策略&lt;/h2&gt;&lt;p&gt;在实际部署中，没有一种方案能解决所有问题。以下是根据不同场景的推荐选择：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;高并发短对话（如客服 BOT）：&lt;/strong&gt;优先用 PagedAttention + Prefix Caching，吞吐量优先&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;长上下文任务（如文档分析）：&lt;/strong&gt;搭配 INT8 量化 + Sliding Window Attention，控制显存峰值&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;延迟敏感型应用（如实时语音）：&lt;/strong&gt;使用投机解码（Speculative Decoding）+ 小草稿模型，降低首 token 延迟&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;多用户共享系统提示：&lt;/strong&gt;开启 Shared Prefix KV Cache，可节省 40%~60% 的缓存空间&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;综合来看，&lt;strong&gt;vLLM + PagedAttention + FP8 KV Cache&lt;/strong&gt; 的组合是目前开源生态中性价比最高的方案，适合大多数生产场景。随着 H100/H200 对 FP8 原生支持的普及，FP8 量化将逐步成为新的默认选项。&lt;/p&gt;&lt;p&gt;KV Cache 的优化仍在快速演进，MLA（Multi-head Latent Attention，DeepSeek 提出）等新型注意力架构通过压缩 KV 的维度从根本上减少了缓存体积，有望成为下一代大模型推理的主流方案，值得持续关注。&lt;/p&gt;</description><pubDate>Mon, 03 Aug 2026 08:09:50 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：属性钩子与非对称可见性实战指南</title><link>https://blog.resmic.cn/post/342.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260802080244178562896499050.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;p&gt;PHP 8.4 于2024年11月21日正式发布，这是一个充满惊喜的版本。从属性钩子到非对称可见性，从新的数组函数到 HTML 解析器改进，PHP 8.4 带来了许多让开发者期待已久的特性。本文将通过实战代码示例，带你全面了解这些新特性。&lt;/p&gt;&lt;h2&gt;一、属性钩子（Property Hooks）&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 最重磅的新特性之一，借鉴了 Kotlin 和 C# 的设计理念，允许在类属性上直接定义 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt; 操作逻辑，告别冗长的 getter/setter 方法。&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$name&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;strtoupper($this-&amp;gt;name);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set(string&amp;nbsp;$value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(strlen($value)&amp;nbsp;&amp;lt;&amp;nbsp;2)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;ValueError(&amp;#39;名称至少需要2个字符&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;$value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$email&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set(string&amp;nbsp;$value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!filter_var($value,&amp;nbsp;FILTER_VALIDATE_EMAIL))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;ValueError(&amp;#39;邮箱格式不正确&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;email&amp;nbsp;=&amp;nbsp;strtolower($value);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User();
$user-&amp;gt;name&amp;nbsp;=&amp;nbsp;&amp;#39;alice&amp;#39;;
echo&amp;nbsp;$user-&amp;gt;name;&amp;nbsp;//&amp;nbsp;输出:&amp;nbsp;ALICE

$user-&amp;gt;email&amp;nbsp;=&amp;nbsp;&amp;#39;Alice@Example.COM&amp;#39;;
echo&amp;nbsp;$user-&amp;gt;email;&amp;nbsp;//&amp;nbsp;输出:&amp;nbsp;alice@example.com&lt;/pre&gt;&lt;p&gt;属性钩子的优势在于：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;代码更简洁，无需单独定义 getter/setter 方法&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;访问属性时自动触发钩子逻辑&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;支持只定义 &lt;code&gt;get&lt;/code&gt; 或只定义 &lt;code&gt;set&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;接口（Interface）中可以声明带钩子的属性&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;二、非对称可见性（Asymmetric Visibility）&lt;/h2&gt;&lt;p&gt;非对称可见性允许为属性的读取和写入设置不同的访问级别。这在构建不可变或半不可变对象时非常有用。&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;Order&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开可读，但只能在类内部修改
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;private(set)&amp;nbsp;int&amp;nbsp;$id;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开可读，只能在类或子类中修改
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;protected(set)&amp;nbsp;string&amp;nbsp;$status&amp;nbsp;=&amp;nbsp;&amp;#39;pending&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;受保护的读，只能在类内部写
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected&amp;nbsp;private(set)&amp;nbsp;array&amp;nbsp;$items&amp;nbsp;=&amp;nbsp;[];

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(int&amp;nbsp;$id)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;id&amp;nbsp;=&amp;nbsp;$id;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;addItem(string&amp;nbsp;$item):&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;items[]&amp;nbsp;=&amp;nbsp;$item;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;status&amp;nbsp;=&amp;nbsp;&amp;#39;processing&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$order&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Order(1001);
echo&amp;nbsp;$order-&amp;gt;id;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;正常读取:&amp;nbsp;1001
echo&amp;nbsp;$order-&amp;gt;status;&amp;nbsp;//&amp;nbsp;正常读取:&amp;nbsp;pending

//&amp;nbsp;$order-&amp;gt;id&amp;nbsp;=&amp;nbsp;2000;&amp;nbsp;//&amp;nbsp;报错！外部无法修改
//&amp;nbsp;$order-&amp;gt;status&amp;nbsp;=&amp;nbsp;&amp;#39;shipped&amp;#39;;&amp;nbsp;//&amp;nbsp;报错！外部无法修改&lt;/pre&gt;&lt;p&gt;非对称可见性的核心使用场景：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;构建领域模型时保护内部状态&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;替代繁琐的 readonly 属性限制&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;配合属性钩子实现更细粒度的访问控制&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;三、new 表达式不再需要括号&lt;/h2&gt;&lt;p&gt;PHP 8.4 之前，在 &lt;code&gt;new&lt;/code&gt; 表达式上直接调用方法需要额外的括号，现在可以直接链式调用，代码更加简洁优雅。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;之前
$result&amp;nbsp;=&amp;nbsp;(new&amp;nbsp;MyBuilder())-&amp;gt;build()-&amp;gt;execute();

//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;之后，无需括号
$result&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MyBuilder()-&amp;gt;build()-&amp;gt;execute();

//&amp;nbsp;实际应用示例
class&amp;nbsp;QueryBuilder&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;array&amp;nbsp;$conditions&amp;nbsp;=&amp;nbsp;[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;?int&amp;nbsp;$limitValue&amp;nbsp;=&amp;nbsp;null;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;where(string&amp;nbsp;$condition):&amp;nbsp;static&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;conditions[]&amp;nbsp;=&amp;nbsp;$condition;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;$this;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;limit(int&amp;nbsp;$n):&amp;nbsp;static&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;limitValue&amp;nbsp;=&amp;nbsp;$n;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;$this;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;toSQL():&amp;nbsp;string&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$where&amp;nbsp;=&amp;nbsp;$this-&amp;gt;conditions&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;?&amp;nbsp;&amp;#39;WHERE&amp;nbsp;&amp;#39;&amp;nbsp;.&amp;nbsp;implode(&amp;#39;&amp;nbsp;AND&amp;nbsp;&amp;#39;,&amp;nbsp;$this-&amp;gt;conditions)&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;&amp;#39;&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$limit&amp;nbsp;=&amp;nbsp;$this-&amp;gt;limitValue&amp;nbsp;?&amp;nbsp;&amp;quot;LIMIT&amp;nbsp;{$this-&amp;gt;limitValue}&amp;quot;&amp;nbsp;:&amp;nbsp;&amp;#39;&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;trim(&amp;quot;SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;users&amp;nbsp;$where&amp;nbsp;$limit&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;优雅写法
$sql&amp;nbsp;=&amp;nbsp;new&amp;nbsp;QueryBuilder()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;where(&amp;#39;age&amp;nbsp;&amp;gt;&amp;nbsp;18&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;where(&amp;#39;status&amp;nbsp;=&amp;nbsp;&amp;quot;active&amp;quot;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;limit(10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;toSQL();

echo&amp;nbsp;$sql;
//&amp;nbsp;SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;users&amp;nbsp;WHERE&amp;nbsp;age&amp;nbsp;&amp;gt;&amp;nbsp;18&amp;nbsp;AND&amp;nbsp;status&amp;nbsp;=&amp;nbsp;&amp;quot;active&amp;quot;&amp;nbsp;LIMIT&amp;nbsp;10&lt;/pre&gt;&lt;h2&gt;四、全新数组函数：array_find 系列&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了 4 个期待已久的数组函数，大幅简化数组查找逻辑：&lt;/p&gt;&lt;pre&gt;$users&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;25,&amp;nbsp;&amp;#39;vip&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;true],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;李四&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;17,&amp;nbsp;&amp;#39;vip&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;false],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;王五&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;30,&amp;nbsp;&amp;#39;vip&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;true],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;赵六&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;15,&amp;nbsp;&amp;#39;vip&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;false],
];

//&amp;nbsp;array_find:&amp;nbsp;找到第一个满足条件的元素
$firstVip&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;vip&amp;#39;]);
//&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;25,&amp;nbsp;&amp;#39;vip&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;true]

//&amp;nbsp;array_find_key:&amp;nbsp;找到第一个满足条件的键
$firstAdultKey&amp;nbsp;=&amp;nbsp;array_find_key($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;gt;=&amp;nbsp;18);
//&amp;nbsp;0

//&amp;nbsp;array_any:&amp;nbsp;是否存在满足条件的元素
$hasMinor&amp;nbsp;=&amp;nbsp;array_any($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;lt;&amp;nbsp;18);
//&amp;nbsp;true

//&amp;nbsp;array_all:&amp;nbsp;是否所有元素都满足条件
$allAdults&amp;nbsp;=&amp;nbsp;array_all($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;gt;=&amp;nbsp;18);
//&amp;nbsp;false

echo&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;gt;=&amp;nbsp;18)[&amp;#39;name&amp;#39;];&amp;nbsp;//&amp;nbsp;张三&lt;/pre&gt;&lt;p&gt;这四个函数的加入，让数组操作代码更具可读性，避免了手写 &lt;code&gt;foreach&lt;/code&gt; 循环或使用 &lt;code&gt;array_filter&lt;/code&gt; + &lt;code&gt;reset&lt;/code&gt; 的繁琐写法。&lt;/p&gt;&lt;h2&gt;五、升级建议与兼容性说明&lt;/h2&gt;&lt;p&gt;PHP 8.4 在向前兼容性方面表现优异，大多数 PHP 8.x 项目可以平滑升级。但仍需注意以下几点：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;废弃警告：&lt;/strong&gt;部分隐式可空参数类型声明已被废弃，如 &lt;code&gt;function foo(string $a = null)&lt;/code&gt; 需改为 &lt;code&gt;function foo(?string $a = null)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GD 扩展变化：&lt;/strong&gt;&lt;code&gt;imagejpeg()&lt;/code&gt; 等函数的 quality 参数默认值有所调整&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;新的 HTML5 解析器：&lt;/strong&gt;基于 Lexbor 库，对不规范 HTML 的解析行为有细微差异&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;PHP 8.4 最低要求：&lt;/strong&gt;需要 GCC 7+ 或 Clang 6+，建议在全面测试后再迁移生产环境&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;总体来看，PHP 8.4 是一个成熟度极高的版本。属性钩子和非对称可见性让 PHP 在面向对象编程方面更上一层楼，新的数组函数和语法糖进一步提升了开发体验。建议所有 PHP 开发者尽快在本地环境试用，感受这些新特性带来的编码效率提升。&lt;/p&gt;</description><pubDate>Sun, 02 Aug 2026 08:03:26 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：属性钩子、懒加载对象与实战指南</title><link>https://blog.resmic.cn/post/341.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260801080315178554259527719.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;PHP 8.4 来了：为何值得关注？&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，是继 PHP 8.3 之后又一次重要的语言演进。这个版本不仅带来了令开发者期待已久的&lt;strong&gt;属性钩子（Property Hooks）&lt;/strong&gt;，还引入了&lt;strong&gt;懒加载对象（Lazy Objects）&lt;/strong&gt;、新的数组函数、以及 &lt;code&gt;new&lt;/code&gt; 关键字无需括号包裹等语法糖，整体上让 PHP 更加现代、更具表达力。&lt;/p&gt;&lt;p&gt;如果你正在维护一个中大型 PHP 项目，或者准备启动新项目，了解这些特性将帮助你写出更简洁、性能更好的代码。本文将逐一拆解 PHP 8.4 的核心新特性，并提供可直接复用的实战示例。&lt;/p&gt;&lt;h2&gt;属性钩子（Property Hooks）：告别冗余的 Getter/Setter&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 最受瞩目的新特性。在此之前，为了控制属性的读写逻辑，我们不得不写大量样板式的 &lt;code&gt;get*()&lt;/code&gt; 和 &lt;code&gt;set*()&lt;/code&gt; 方法。现在，你可以直接在属性声明处定义钩子逻辑：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$name&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;strtoupper($this-&amp;gt;name);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set(string&amp;nbsp;$value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(strlen($value)&amp;nbsp;&amp;lt;&amp;nbsp;2)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\ValueError(&amp;#39;Name&amp;nbsp;must&amp;nbsp;be&amp;nbsp;at&amp;nbsp;least&amp;nbsp;2&amp;nbsp;characters.&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;$value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(string&amp;nbsp;$name)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;$name;&amp;nbsp;//&amp;nbsp;触发&amp;nbsp;set&amp;nbsp;钩子
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User(&amp;#39;alice&amp;#39;);
echo&amp;nbsp;$user-&amp;gt;name;&amp;nbsp;//&amp;nbsp;输出:&amp;nbsp;ALICE&lt;/pre&gt;&lt;p&gt;属性钩子支持 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt; 两种形式，可以单独使用其中一个，也可以同时定义。&lt;code&gt;get&lt;/code&gt; 钩子让属性变为&amp;quot;虚拟只读计算属性&amp;quot;，&lt;code&gt;set&lt;/code&gt; 钩子则可在赋值时进行校验或转换。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;减少样板代码&lt;/strong&gt;：无需再写 &lt;code&gt;getName()&lt;/code&gt; / &lt;code&gt;setName()&lt;/code&gt; 方法对&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;接口可申明钩子&lt;/strong&gt;：接口中可以声明带钩子的属性，强制实现类遵循约束&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;只读属性兼容&lt;/strong&gt;：与 &lt;code&gt;readonly&lt;/code&gt; 属性相比，钩子提供更灵活的控制&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;继承支持&lt;/strong&gt;：子类可以覆盖父类的钩子实现&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;接口中声明属性钩子
interface&amp;nbsp;HasFullName&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$fullName&amp;nbsp;{&amp;nbsp;get;&amp;nbsp;}
}

class&amp;nbsp;Profile&amp;nbsp;implements&amp;nbsp;HasFullName&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$fullName&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;$this-&amp;gt;firstName&amp;nbsp;.&amp;nbsp;&amp;#39;&amp;nbsp;&amp;#39;&amp;nbsp;.&amp;nbsp;$this-&amp;gt;lastName;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$firstName,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$lastName,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{}
}&lt;/pre&gt;&lt;h2&gt;懒加载对象（Lazy Objects）：性能优化利器&lt;/h2&gt;&lt;p&gt;PHP 8.4 在反射 API 中引入了懒加载对象支持，允许你创建一个对象的&amp;quot;占位符&amp;quot;，只有在真正访问其属性或方法时才执行初始化逻辑。这对于依赖注入容器、ORM 延迟加载、以及大型服务对象的初始化优化非常有价值。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;DatabaseConnection&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$dsn,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$user,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$password,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;假设这里有耗时的连接操作
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Connecting&amp;nbsp;to&amp;nbsp;database...\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;query(string&amp;nbsp;$sql):&amp;nbsp;array&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[];&amp;nbsp;//&amp;nbsp;实际执行查询
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;创建懒加载代理：初始化逻辑不会立即执行
$reflector&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ReflectionClass(DatabaseConnection::class);
$db&amp;nbsp;=&amp;nbsp;$reflector-&amp;gt;newLazyGhost(function&amp;nbsp;(DatabaseConnection&amp;nbsp;$instance)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;只有真正使用对象时才调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$instance-&amp;gt;__construct(&amp;#39;mysql:host=localhost&amp;#39;,&amp;nbsp;&amp;#39;root&amp;#39;,&amp;nbsp;&amp;#39;secret&amp;#39;);
});

echo&amp;nbsp;&amp;quot;Object&amp;nbsp;created&amp;nbsp;(no&amp;nbsp;connection&amp;nbsp;yet)\n&amp;quot;;

//&amp;nbsp;只有在这里访问方法时，初始化才会触发
$result&amp;nbsp;=&amp;nbsp;$db-&amp;gt;query(&amp;#39;SELECT&amp;nbsp;1&amp;#39;);&lt;/pre&gt;&lt;p&gt;懒加载对象有两种形式：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy Ghost&lt;/strong&gt;：同一个类的实例，初始化后直接填充属性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy Proxy&lt;/strong&gt;：使用另一个真实对象作为代理目标，适合接口解耦场景&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;新增数组函数：array_find、array_find_key 等&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了 4 个期待已久的数组函数，让数组操作更加直观：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

$users&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;1,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Alice&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;2,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Bob&amp;#39;,&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;editor&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;3,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Carol&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;],
];

//&amp;nbsp;array_find:&amp;nbsp;找到第一个满足条件的元素（找不到返回&amp;nbsp;null）
$firstAdmin&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);
//&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;1,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Alice&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;]

//&amp;nbsp;array_find_key:&amp;nbsp;找到第一个满足条件的键
$firstAdminKey&amp;nbsp;=&amp;nbsp;array_find_key($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);
//&amp;nbsp;0

//&amp;nbsp;array_any:&amp;nbsp;是否存在至少一个满足条件的元素
$hasEditor&amp;nbsp;=&amp;nbsp;array_any($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;editor&amp;#39;);
//&amp;nbsp;true

//&amp;nbsp;array_all:&amp;nbsp;是否所有元素都满足条件
$allAdmins&amp;nbsp;=&amp;nbsp;array_all($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);
//&amp;nbsp;false&lt;/pre&gt;&lt;p&gt;这些函数在语义上比 &lt;code&gt;array_filter&lt;/code&gt; + &lt;code&gt;reset&lt;/code&gt; 的组合更清晰，也避免了空数组时的歧义问题。特别是在处理集合查找逻辑时，代码可读性大幅提升。&lt;/p&gt;&lt;h2&gt;new 表达式无需括号 &amp;amp; 其他语法改进&lt;/h2&gt;&lt;p&gt;PHP 8.4 允许在不加括号的情况下直接链式调用 &lt;code&gt;new&lt;/code&gt; 表达式，消除了之前令人困惑的括号要求：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

//&amp;nbsp;PHP&amp;nbsp;8.3&amp;nbsp;及之前：必须加括号
$result&amp;nbsp;=&amp;nbsp;(new&amp;nbsp;MyBuilder())-&amp;gt;build();

//&amp;nbsp;PHP&amp;nbsp;8.4：直接链式调用
$result&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MyBuilder()-&amp;gt;build();

//&amp;nbsp;支持更复杂的链式
$html&amp;nbsp;=&amp;nbsp;new&amp;nbsp;HtmlBuilder()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;tag(&amp;#39;div&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;class(&amp;#39;container&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;text(&amp;#39;Hello,&amp;nbsp;PHP&amp;nbsp;8.4!&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;render();&lt;/pre&gt;&lt;p&gt;此外还有以下值得关注的改进：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;#[\Deprecated]&lt;/code&gt; 属性&lt;/strong&gt;：可以用原生属性标记弃用方法/函数，替代 PHPDoc &lt;code&gt;@deprecated&lt;/code&gt;，并触发内置废弃警告&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTML5 解析支持&lt;/strong&gt;：&lt;code&gt;Dom\HTMLDocument&lt;/code&gt; 类使用符合 HTML5 规范的解析器，解决旧版 &lt;code&gt;DOMDocument&lt;/code&gt; 对现代 HTML 的解析问题&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;BCMath 对象 API&lt;/strong&gt;：&lt;code&gt;BcMath\Number&lt;/code&gt; 类支持运算符重载，让高精度计算代码更自然&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;JIT 改进&lt;/strong&gt;：PHP 8.4 对 JIT 编译器进行了重构，内存占用更低，启用更简单（&lt;code&gt;opcache.jit=tracing&lt;/code&gt;）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;#[\Deprecated]&amp;nbsp;原生弃用标记
class&amp;nbsp;LegacyApi&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#[\Deprecated(message:&amp;nbsp;&amp;#39;Use&amp;nbsp;newMethod()&amp;nbsp;instead&amp;#39;,&amp;nbsp;since:&amp;nbsp;&amp;#39;2.0&amp;#39;)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;oldMethod():&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;newMethod();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;newMethod():&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;BCMath&amp;nbsp;对象&amp;nbsp;API
use&amp;nbsp;BcMath\Number;
$a&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;10.5&amp;#39;);
$b&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;3.2&amp;#39;);
$result&amp;nbsp;=&amp;nbsp;$a&amp;nbsp;+&amp;nbsp;$b;&amp;nbsp;//&amp;nbsp;不再需要&amp;nbsp;bcadd()，直接用&amp;nbsp;+
echo&amp;nbsp;$result;&amp;nbsp;//&amp;nbsp;13.7&lt;/pre&gt;&lt;h2&gt;升级指南与兼容性注意事项&lt;/h2&gt;&lt;p&gt;PHP 8.4 在兼容性方面整体表现良好，但仍有几个需要注意的破坏性变更：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;隐式类型转换&lt;/strong&gt;：部分边缘情况下的隐式 &lt;code&gt;null&lt;/code&gt; 转换行为调整，需要检查函数参数传递&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GMP 函数&lt;/strong&gt;：&lt;code&gt;gmp_random()&lt;/code&gt; 已被移除，请改用 &lt;code&gt;gmp_random_bits()&lt;/code&gt; 或 &lt;code&gt;gmp_random_range()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;IMAP 扩展&lt;/strong&gt;：&lt;code&gt;imap_*&lt;/code&gt; 系列函数已从核心移出，需要单独安装 &lt;code&gt;ext-imap&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;mysqli 默认行为&lt;/strong&gt;：&lt;code&gt;mysqli_ping()&lt;/code&gt; 和自动重连功能已移除&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;升级前建议使用 &lt;code&gt;phpstan&lt;/code&gt; 或 &lt;code&gt;rector&lt;/code&gt; 扫描代码库：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;使用&amp;nbsp;Rector&amp;nbsp;自动化升级检测
composer&amp;nbsp;require&amp;nbsp;rector/rector&amp;nbsp;--dev

#&amp;nbsp;初始化配置
./vendor/bin/rector&amp;nbsp;init

#&amp;nbsp;在&amp;nbsp;rector.php&amp;nbsp;中启用&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;规则集
#&amp;nbsp;然后运行检测（--dry-run&amp;nbsp;不修改文件）
./vendor/bin/rector&amp;nbsp;process&amp;nbsp;src&amp;nbsp;--dry-run&lt;/pre&gt;&lt;p&gt;总体而言，PHP 8.4 是一次值得期待的升级。属性钩子和懒加载对象的引入，让 PHP 在现代应用开发中更具竞争力。建议在测试环境验证通过后，尽快将生产环境迁移到 PHP 8.4，以享受更好的性能和语言特性支持。&lt;/p&gt;</description><pubDate>Sat, 01 Aug 2026 08:08:31 +0800</pubDate></item><item><title>PHP 8.4 新特性实战解析：属性钩子、不对称可见性与数组新函数</title><link>https://blog.resmic.cn/post/340.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/07/20260731080520178545632043655.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;PHP 8.4 重磅发布：开发者必须了解的核心新特性&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，这是 PHP 近年来最具突破性的版本之一。本文将带你深入了解其中最实用的新特性，并通过真实代码示例展示如何在项目中快速落地。&lt;/p&gt;&lt;p&gt;无论你是在维护大型 Laravel/Symfony 项目，还是编写独立的 PHP 脚本，PHP 8.4 的这些改进都能显著提升代码的可读性和开发效率。&lt;/p&gt;&lt;h2&gt;属性钩子（Property Hooks）：告别繁琐的 Getter/Setter&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 中最受期待的特性之一，它允许开发者直接在属性声明中定义 get/set 逻辑，彻底简化了 VO（值对象）和 DTO 的写法。&lt;/p&gt;&lt;p&gt;传统写法需要大量样板代码：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;旧写法：繁琐的&amp;nbsp;Getter/Setter
class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$_name;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;getName():&amp;nbsp;string&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;$this-&amp;gt;_name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;setName(string&amp;nbsp;$name):&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(empty(trim($name)))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\InvalidArgumentException(&amp;#39;Name&amp;nbsp;cannot&amp;nbsp;be&amp;nbsp;empty&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;_name&amp;nbsp;=&amp;nbsp;trim($name);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;使用 PHP 8.4 的属性钩子，代码变得极为简洁：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;新写法：属性钩子
class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$name&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;$this-&amp;gt;name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(empty(trim($value)))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\InvalidArgumentException(&amp;#39;Name&amp;nbsp;cannot&amp;nbsp;be&amp;nbsp;empty&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;trim($value);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User();
$user-&amp;gt;name&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;nbsp;&amp;nbsp;Alice&amp;nbsp;&amp;nbsp;&amp;#39;;&amp;nbsp;&amp;nbsp;//&amp;nbsp;自动&amp;nbsp;trim
echo&amp;nbsp;$user-&amp;gt;name;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;输出：Alice&lt;/pre&gt;&lt;p&gt;属性钩子同样支持只读场景，配合构造器提升（constructor promotion）使用更加优雅：&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;Temperature&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;float&amp;nbsp;$celsius&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;$this-&amp;gt;celsius;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set&amp;nbsp;=&amp;gt;&amp;nbsp;round($value,&amp;nbsp;2);&amp;nbsp;//&amp;nbsp;自动四舍五入保留两位小数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;float&amp;nbsp;$fahrenheit&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;$this-&amp;gt;celsius&amp;nbsp;*&amp;nbsp;9/5&amp;nbsp;+&amp;nbsp;32;&amp;nbsp;//&amp;nbsp;计算属性，无&amp;nbsp;set
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$temp&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Temperature();
$temp-&amp;gt;celsius&amp;nbsp;=&amp;nbsp;36.6789;
echo&amp;nbsp;$temp-&amp;gt;celsius;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;36.68
echo&amp;nbsp;$temp-&amp;gt;fahrenheit;&amp;nbsp;//&amp;nbsp;97.82&lt;/pre&gt;&lt;h2&gt;不对称可见性修饰符（Asymmetric Visibility）&lt;/h2&gt;&lt;p&gt;PHP 8.4 引入了不对称可见性修饰符，允许属性的读写权限分别设置。这在实现不可变对象模式时非常有用。&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;Order&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;private(set)&amp;nbsp;int&amp;nbsp;$id;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开可读，仅内部可写
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;protected(set)&amp;nbsp;string&amp;nbsp;$status;&amp;nbsp;//&amp;nbsp;公开可读，子类可写

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(int&amp;nbsp;$id,&amp;nbsp;string&amp;nbsp;$status&amp;nbsp;=&amp;nbsp;&amp;#39;pending&amp;#39;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;id&amp;nbsp;=&amp;nbsp;$id;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;status&amp;nbsp;=&amp;nbsp;$status;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;confirm():&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;status&amp;nbsp;=&amp;nbsp;&amp;#39;confirmed&amp;#39;;&amp;nbsp;//&amp;nbsp;内部可以修改
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$order&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Order(1001);
echo&amp;nbsp;$order-&amp;gt;id;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;✅&amp;nbsp;可读
$order-&amp;gt;id&amp;nbsp;=&amp;nbsp;999;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;❌&amp;nbsp;Fatal&amp;nbsp;Error：不可在外部写入&lt;/pre&gt;&lt;p&gt;不对称可见性与 readonly 的区别在于，readonly 只允许初始化一次，而 &lt;code&gt;private(set)&lt;/code&gt; 允许类内部多次修改，更灵活。&lt;/p&gt;&lt;h2&gt;全新的数组操作函数&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了一批实用的数组函数，填补了之前版本的空白，大幅减少手动循环的需要。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_find()&lt;/strong&gt;：返回第一个满足条件的元素值&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_find_key()&lt;/strong&gt;：返回第一个满足条件的元素键名&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_any()&lt;/strong&gt;：判断是否存在至少一个满足条件的元素&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_all()&lt;/strong&gt;：判断是否所有元素都满足条件&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;$users&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Alice&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;28,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Bob&amp;#39;,&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;35,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;user&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Carol&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;22,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;user&amp;#39;],
];

//&amp;nbsp;找到第一个&amp;nbsp;admin&amp;nbsp;用户
$admin&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);
echo&amp;nbsp;$admin[&amp;#39;name&amp;#39;];&amp;nbsp;//&amp;nbsp;Alice

//&amp;nbsp;是否有未成年人（age&amp;nbsp;&amp;lt;&amp;nbsp;18）
$hasMinor&amp;nbsp;=&amp;nbsp;array_any($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;lt;&amp;nbsp;18);
var_dump($hasMinor);&amp;nbsp;//&amp;nbsp;bool(false)

//&amp;nbsp;所有用户是否都已成年
$allAdult&amp;nbsp;=&amp;nbsp;array_all($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;gt;=&amp;nbsp;18);
var_dump($allAdult);&amp;nbsp;//&amp;nbsp;bool(true)

//&amp;nbsp;找到&amp;nbsp;Bob&amp;nbsp;的下标
$bobKey&amp;nbsp;=&amp;nbsp;array_find_key($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;name&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;Bob&amp;#39;);
echo&amp;nbsp;$bobKey;&amp;nbsp;//&amp;nbsp;1&lt;/pre&gt;&lt;p&gt;这些函数比手写 &lt;code&gt;array_filter&lt;/code&gt; + &lt;code&gt;array_values&lt;/code&gt; 组合更直观，语义也更清晰。&lt;/p&gt;&lt;h2&gt;new 表达式链式调用 &amp;amp; 其他实用改进&lt;/h2&gt;&lt;p&gt;PHP 8.4 终于支持对 &lt;code&gt;new&lt;/code&gt; 表达式直接进行方法链调用，无需再套一层括号：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;PHP&amp;nbsp;8.3&amp;nbsp;及之前需要括号
$result&amp;nbsp;=&amp;nbsp;(new&amp;nbsp;QueryBuilder())-&amp;gt;select(&amp;#39;*&amp;#39;)-&amp;gt;from(&amp;#39;users&amp;#39;)-&amp;gt;get();

//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;可以直接链式调用（无需括号）
$result&amp;nbsp;=&amp;nbsp;new&amp;nbsp;QueryBuilder()-&amp;gt;select(&amp;#39;*&amp;#39;)-&amp;gt;from(&amp;#39;users&amp;#39;)-&amp;gt;get();&lt;/pre&gt;&lt;p&gt;此外，PHP 8.4 还带来了以下改进：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy Objects（惰性对象）&lt;/strong&gt;：内置对象懒加载支持，适合实现代理模式和依赖注入容器优化&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;新的 HTML5 解析器&lt;/strong&gt;：&lt;code&gt;Dom\HTMLDocument&lt;/code&gt; 基于 libgumbo 解析，完全兼容 HTML5 标准，取代旧的 libxml HTML 模式&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;BCMath 对象 API&lt;/strong&gt;：高精度数学运算支持运算符重载，数值计算代码更简洁&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;JIT 性能持续提升&lt;/strong&gt;：函数调用与循环场景下性能较 PHP 8.3 再提升约 5~10%&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;新的&amp;nbsp;HTML5&amp;nbsp;解析器示例
$dom&amp;nbsp;=&amp;nbsp;Dom\HTMLDocument::createFromString(&amp;#39;Hello&amp;nbsp;&amp;amp;&amp;nbsp;World&amp;#39;);
$h1&amp;nbsp;=&amp;nbsp;$dom-&amp;gt;querySelector(&amp;#39;h1&amp;#39;);
echo&amp;nbsp;$h1-&amp;gt;textContent;&amp;nbsp;//&amp;nbsp;Hello&amp;nbsp;&amp;amp;&amp;nbsp;World（正确处理&amp;nbsp;HTML5&amp;nbsp;实体）

//&amp;nbsp;BCMath&amp;nbsp;对象&amp;nbsp;API
use&amp;nbsp;BcMath\Number;
$a&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;0.1&amp;#39;);
$b&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;0.2&amp;#39;);
echo&amp;nbsp;$a&amp;nbsp;+&amp;nbsp;$b;&amp;nbsp;//&amp;nbsp;0.3（精确计算，无浮点误差）&lt;/pre&gt;&lt;h2&gt;升级建议与兼容性注意事项&lt;/h2&gt;&lt;p&gt;PHP 8.4 整体向下兼容性良好，但升级前仍需注意以下几点：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;废弃隐式可空类型&lt;/strong&gt;：&lt;code&gt;function foo(string $x = null)&lt;/code&gt; 需改为 &lt;code&gt;function foo(?string $x = null)&lt;/code&gt;，否则触发废弃警告&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GMP 扩展变更&lt;/strong&gt;：&lt;code&gt;GMP&lt;/code&gt; 对象不再可序列化&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;LDAP 函数变更&lt;/strong&gt;：部分旧版 LDAP 函数已移除&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Composer 2.7+&lt;/strong&gt;：建议同步升级 Composer 版本以获取最佳兼容性&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;建议在升级前运行 &lt;code&gt;php --version&lt;/code&gt; 确认环境，并使用 &lt;a href=&quot;https://github.com/rectorphp/rector&quot; target=&quot;_blank&quot;&gt;Rector&lt;/a&gt; 自动化迁移工具扫描代码库：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;安装&amp;nbsp;Rector
composer&amp;nbsp;require&amp;nbsp;rector/rector&amp;nbsp;--dev

#&amp;nbsp;运行&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;升级规则检查
./vendor/bin/rector&amp;nbsp;process&amp;nbsp;src&amp;nbsp;--dry-run&amp;nbsp;--set&amp;nbsp;php84&lt;/pre&gt;&lt;p&gt;PHP 8.4 的这些改进让 PHP 在现代化语言特性方面又迈出了重要一步。属性钩子和不对称可见性尤其值得关注，它们将改变我们编写数据模型的方式。建议在测试环境中提前体验，为正式升级做好准备。&lt;/p&gt;</description><pubDate>Fri, 31 Jul 2026 08:05:39 +0800</pubDate></item><item><title>Vibe Coding 实战指南：用自然语言驱动 AI 编程的新范式</title><link>https://blog.resmic.cn/post/339.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/07/20260729080305178528338537110.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;什么是 Vibe Coding？&lt;/h2&gt;&lt;p&gt;2025年，OpenAI 联合创始人 Andrej Karpathy 提出了&amp;quot;Vibe Coding&amp;quot;（氛围编程）这一概念，迅速在开发者社区引发广泛讨论。Vibe Coding 的核心思想是：&lt;strong&gt;开发者以自然语言描述意图，AI 负责将其转化为可执行代码&lt;/strong&gt;，人类更多扮演&amp;quot;需求方&amp;quot;和&amp;quot;审查者&amp;quot;的角色，而非亲自敲每一行代码。&lt;/p&gt;&lt;p&gt;这与传统编程范式有本质区别。传统开发中，程序员需要精通语言语法、框架 API、设计模式等大量细节；而在 Vibe Coding 中，你只需要清晰地描述&amp;quot;我要什么&amp;quot;，AI 工具会帮你处理&amp;quot;怎么实现&amp;quot;。这种范式转变大幅降低了编程门槛，同时也让有经验的开发者能以数倍速度完成原型开发。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;自然语言驱动&lt;/strong&gt;：用中英文描述功能需求，AI 生成完整代码&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;迭代对话式开发&lt;/strong&gt;：通过多轮对话不断完善和修改实现&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;人机协作&lt;/strong&gt;：开发者负责架构决策与代码审查，AI 负责具体实现&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;低门槛高效率&lt;/strong&gt;：非专业开发者也可构建功能完整的应用&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;主流 Vibe Coding 工具全景&lt;/h2&gt;&lt;p&gt;目前市场上涌现了大量支持 Vibe Coding 的工具，各有侧重。选择合适的工具是提升开发效率的第一步。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt;：最受专业开发者欢迎的 AI IDE，基于 VSCode 深度改造，支持全代码库感知对话（@Codebase）、多文件编辑、Composer 模式等，月活用户已超 100 万。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;：微软 + OpenAI 出品，深度集成 VS Code / JetBrains，行内补全体验一流，2025 年新增 Agent 模式支持多步骤任务。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;：Anthropic 推出的命令行 AI 编程助手，支持直接操作文件系统与 shell，适合复杂重构和大型项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bolt.new / v0.dev&lt;/strong&gt;：面向全栈 Web 应用的零代码平台，从需求描述到可预览的 React 应用只需几十秒，适合快速原型验证。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Windsurf（前 Codeium）&lt;/strong&gt;：主打&amp;quot;Cascade&amp;quot;智能体模式，能自主规划多步骤开发任务，与 Cursor 形成竞争。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Replit Agent&lt;/strong&gt;：云端一体化开发平台，从代码生成到部署全程 AI 辅助，适合个人项目和学习场景。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;选型建议：专业开发者推荐 &lt;strong&gt;Cursor&lt;/strong&gt;；重度使用 GitHub 生态选 &lt;strong&gt;Copilot&lt;/strong&gt;；快速做 Web 原型选 &lt;strong&gt;Bolt.new&lt;/strong&gt;；需要命令行能力选 &lt;strong&gt;Claude Code&lt;/strong&gt;。&lt;/p&gt;&lt;h2&gt;核心实践技巧：如何写好 Prompt&lt;/h2&gt;&lt;p&gt;Vibe Coding 的效果好坏，80% 取决于 Prompt 质量。以下是经过大量实践总结的高效 Prompt 写法：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;明确技术栈&lt;/strong&gt;：告诉 AI 你使用的语言、框架、版本，避免 AI 猜测，例如&amp;quot;用 Python 3.12 + FastAPI + SQLAlchemy 2.0&amp;quot;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;描述输入输出&lt;/strong&gt;：说清楚函数/接口的输入参数和期望输出格式，而非仅描述功能名称&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;提供上下文&lt;/strong&gt;：粘贴相关的现有代码、数据库 Schema 或错误信息，让 AI 理解全局&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;分步拆解复杂任务&lt;/strong&gt;：不要一次让 AI 实现整个系统，拆成小任务逐步完成&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;使用示例驱动&lt;/strong&gt;：提供输入输出示例，比抽象描述更精准&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;#&amp;nbsp;好的&amp;nbsp;Prompt&amp;nbsp;示例
#&amp;nbsp;背景：FastAPI&amp;nbsp;项目，使用&amp;nbsp;PostgreSQL，已有&amp;nbsp;User&amp;nbsp;模型
#&amp;nbsp;需求：实现用户注册接口

请实现一个&amp;nbsp;POST&amp;nbsp;/api/v1/register&amp;nbsp;接口，要求：
-&amp;nbsp;接收&amp;nbsp;JSON:&amp;nbsp;{&amp;quot;username&amp;quot;:&amp;nbsp;str,&amp;nbsp;&amp;quot;email&amp;quot;:&amp;nbsp;str,&amp;nbsp;&amp;quot;password&amp;quot;:&amp;nbsp;str}
-&amp;nbsp;密码使用&amp;nbsp;bcrypt&amp;nbsp;哈希后存储
-&amp;nbsp;email&amp;nbsp;唯一性校验（重复时返回&amp;nbsp;400）
-&amp;nbsp;成功返回&amp;nbsp;201&amp;nbsp;和&amp;nbsp;{&amp;quot;id&amp;quot;:&amp;nbsp;int,&amp;nbsp;&amp;quot;username&amp;quot;:&amp;nbsp;str,&amp;nbsp;&amp;quot;email&amp;quot;:&amp;nbsp;str}
-&amp;nbsp;失败返回标准&amp;nbsp;{&amp;quot;detail&amp;quot;:&amp;nbsp;str}&amp;nbsp;错误格式
-&amp;nbsp;使用现有的&amp;nbsp;UserService&amp;nbsp;类（见&amp;nbsp;services/user.py）&lt;/pre&gt;&lt;h2&gt;完整工作流实战：从需求到上线&lt;/h2&gt;&lt;p&gt;以构建一个&amp;quot;个人书签管理 Web App&amp;quot;为例，演示完整的 Vibe Coding 工作流：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;Step&amp;nbsp;1：用&amp;nbsp;Bolt.new&amp;nbsp;生成初始原型
Prompt:&amp;nbsp;&amp;quot;创建一个书签管理应用，支持添加URL、自动获取标题和favicon、
按标签分类、全文搜索。使用&amp;nbsp;React&amp;nbsp;+&amp;nbsp;Tailwind，数据本地存储。&amp;quot;

#&amp;nbsp;30秒内得到可运行的基础版本

#&amp;nbsp;Step&amp;nbsp;2：在&amp;nbsp;Cursor&amp;nbsp;中继续完善
@Codebase&amp;nbsp;添加后端&amp;nbsp;API，使用&amp;nbsp;FastAPI&amp;nbsp;+&amp;nbsp;SQLite，
支持多用户，添加&amp;nbsp;JWT&amp;nbsp;认证

#&amp;nbsp;Step&amp;nbsp;3：让&amp;nbsp;AI&amp;nbsp;生成测试
为所有&amp;nbsp;API&amp;nbsp;端点生成&amp;nbsp;pytest&amp;nbsp;测试用例，
覆盖正常流程和边界情况

#&amp;nbsp;Step&amp;nbsp;4：部署配置
生成&amp;nbsp;Dockerfile&amp;nbsp;和&amp;nbsp;docker-compose.yml，
包含&amp;nbsp;Nginx&amp;nbsp;反向代理配置&lt;/pre&gt;&lt;p&gt;整个过程预计 2-4 小时即可完成一个生产级别的小型应用，而传统方式可能需要 1-2 周。&lt;/p&gt;&lt;h2&gt;Vibe Coding 的局限与风险&lt;/h2&gt;&lt;p&gt;尽管 Vibe Coding 带来了巨大的效率提升，但也存在不可忽视的局限性，实践中需要格外注意：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;代码质量参差不齐&lt;/strong&gt;：AI 生成的代码可能存在冗余、不符合最佳实践，甚至引入安全漏洞，必须经过人工审查&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;幻觉与错误&lt;/strong&gt;：AI 可能生成看似合理但实际错误的代码，尤其是涉及边界条件、并发、事务等复杂场景&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;依赖过时知识&lt;/strong&gt;：模型训练数据有截止日期，对最新框架版本或 API 可能不熟悉&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;安全风险&lt;/strong&gt;：对于涉及认证、加密、SQL 查询的代码，必须独立审查，AI 经常忽略 SQL 注入、XSS 等安全问题&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;技能退化风险&lt;/strong&gt;：过度依赖 AI 可能导致开发者基础能力退化，建议保持对核心技术的主动学习&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;知识产权争议&lt;/strong&gt;：AI 生成代码的版权归属仍存在法律灰色地带&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;最佳实践：让 Vibe Coding 真正提效&lt;/h2&gt;&lt;p&gt;综合社区经验，以下原则能帮助你最大化 Vibe Coding 的价值：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;仍要理解代码&lt;/strong&gt;：不能完全当&amp;quot;黑盒&amp;quot;使用，至少要能读懂 AI 生成的代码&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;建立 Review 习惯&lt;/strong&gt;：每次 AI 生成代码后，做简短的安全和逻辑 Review&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;测试驱动&lt;/strong&gt;：要求 AI 同时生成测试用例，用测试验证功能正确性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;版本控制&lt;/strong&gt;：频繁 commit，便于回滚 AI 引入的问题&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;渐进采用&lt;/strong&gt;：先从重复性、低风险的代码开始（如 CRUD、数据转换），再扩展到核心业务逻辑&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;组合使用多种工具&lt;/strong&gt;：不同场景选择最合适的工具，不要一把锤子打天下&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Vibe Coding 不是编程的终点，而是编程进化的新阶段。它将开发者从繁琐的实现细节中解放出来，让我们能够将更多精力投入到架构设计、用户体验和业务创新中。掌握这一范式，将是未来几年开发者竞争力的核心差异之一。&lt;/p&gt;&lt;h2&gt;结语&lt;/h2&gt;&lt;p&gt;Vibe Coding 正在重新定义&amp;quot;会编程&amp;quot;的含义。当 AI 能够处理大部分代码实现时，开发者的核心价值转向了：&lt;strong&gt;清晰表达需求的能力、审查和优化代码的判断力、以及构建复杂系统的架构思维&lt;/strong&gt;。这不是程序员被取代的时代，而是程序员能力被放大的时代。&lt;/p&gt;&lt;p&gt;从今天开始，选择一款适合自己的 Vibe Coding 工具，在真实项目中实践起来吧。&lt;/p&gt;</description><pubDate>Wed, 29 Jul 2026 08:08:09 +0800</pubDate></item><item><title>Jetpack Compose 动画系统全解析：从基础到高级动效实战</title><link>https://blog.resmic.cn/post/338.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/07/20260728080519178519711953272.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;前言：为什么动画在 Android 开发中如此重要？&lt;/h2&gt;&lt;p&gt;在移动应用开发中，动画不仅仅是视觉装饰，更是用户体验的核心组成部分。一个流畅自然的动画能够让用户感知到操作反馈，降低认知负担，使应用看起来更加专业和精致。Google Material Design 规范中对动画的定义明确指出：&lt;strong&gt;动画是连接不同状态的桥梁&lt;/strong&gt;，它传递信息、引导注意力、增强空间感知。&lt;/p&gt;&lt;p&gt;随着 Jetpack Compose 的正式发布，Android 动画系统迎来了全新的声明式编程范式。相比传统的 View 动画系统（ObjectAnimator、ValueAnimator、Transition），Compose 动画更加简洁、可组合、可预测。本文将系统梳理 Compose 动画 API 体系，从基础用法到高级场景，配合实际代码示例，帮助你彻底掌握 Compose 动画开发。&lt;/p&gt;&lt;h2&gt;Compose 动画 API 全景图&lt;/h2&gt;&lt;p&gt;Compose 提供了一套分层设计的动画 API，从简单到复杂可以分为以下几个层次：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;高级 API（推荐优先使用）&lt;/strong&gt;：&lt;code&gt;AnimatedVisibility&lt;/code&gt;、&lt;code&gt;AnimatedContent&lt;/code&gt;、&lt;code&gt;Crossfade&lt;/code&gt;、&lt;code&gt;animateContentSize&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;animateXxxAsState 系列&lt;/strong&gt;：&lt;code&gt;animateFloatAsState&lt;/code&gt;、&lt;code&gt;animateColorAsState&lt;/code&gt;、&lt;code&gt;animateDpAsState&lt;/code&gt; 等&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transition API&lt;/strong&gt;：&lt;code&gt;updateTransition&lt;/code&gt;，用于多属性联动动画&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;无限循环动画&lt;/strong&gt;：&lt;code&gt;rememberInfiniteTransition&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;底层 API&lt;/strong&gt;：&lt;code&gt;Animatable&lt;/code&gt;，用于精细控制和手势驱动动画&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;共享元素动画&lt;/strong&gt;：&lt;code&gt;SharedTransitionLayout&lt;/code&gt;（Compose 1.7+）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;选择哪个 API 取决于你的使用场景：简单的状态切换用高级 API，多属性联动用 Transition，需要精确控制或配合手势则用 Animatable。&lt;/p&gt;&lt;h2&gt;animateXxxAsState：最简单的状态动画&lt;/h2&gt;&lt;p&gt;&lt;code&gt;animateXxxAsState&lt;/code&gt; 系列是 Compose 中最常用的动画 API，它的工作原理非常直观：当目标值变化时，自动以动画过渡到新值。&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;AnimatedHeartButton()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;liked&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;mutableStateOf(false)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;动画化尺寸和颜色
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;iconSize&amp;nbsp;by&amp;nbsp;animateDpAsState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(liked)&amp;nbsp;48.dp&amp;nbsp;else&amp;nbsp;32.dp,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;spring(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dampingRatio&amp;nbsp;=&amp;nbsp;Spring.DampingRatioMediumBouncy,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stiffness&amp;nbsp;=&amp;nbsp;Spring.StiffnessLow
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;heart_size&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;iconColor&amp;nbsp;by&amp;nbsp;animateColorAsState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(liked)&amp;nbsp;Color.Red&amp;nbsp;else&amp;nbsp;Color.Gray,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;tween(durationMillis&amp;nbsp;=&amp;nbsp;300),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;heart_color&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IconButton(onClick&amp;nbsp;=&amp;nbsp;{&amp;nbsp;liked&amp;nbsp;=&amp;nbsp;!liked&amp;nbsp;})&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Icon(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;imageVector&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(liked)&amp;nbsp;Icons.Filled.Favorite&amp;nbsp;else&amp;nbsp;Icons.Outlined.FavoriteBorder,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;&amp;quot;Like&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.size(iconSize),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tint&amp;nbsp;=&amp;nbsp;iconColor
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;注意 &lt;code&gt;animationSpec&lt;/code&gt; 参数：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;tween&lt;/code&gt;：基于时间的线性或缓动动画，适合大多数场景&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;spring&lt;/code&gt;：基于物理的弹簧动画，更自然，&lt;strong&gt;推荐用于 UI 元素移动&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;keyframes&lt;/code&gt;：关键帧动画，可以精确控制中间状态&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;snap&lt;/code&gt;：无动画立即跳转&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;AnimatedVisibility 与 AnimatedContent：内容切换动画&lt;/h2&gt;&lt;p&gt;&lt;code&gt;AnimatedVisibility&lt;/code&gt; 用于控制组件的显示/隐藏动画，支持自定义进入和退出效果：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;ExpandableCard(title:&amp;nbsp;String,&amp;nbsp;content:&amp;nbsp;String)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;expanded&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;mutableStateOf(false)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Card(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.fillMaxWidth()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.clickable&amp;nbsp;{&amp;nbsp;expanded&amp;nbsp;=&amp;nbsp;!expanded&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Column(modifier&amp;nbsp;=&amp;nbsp;Modifier.padding(16.dp))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Row(verticalAlignment&amp;nbsp;=&amp;nbsp;Alignment.CenterVertically)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(text&amp;nbsp;=&amp;nbsp;title,&amp;nbsp;style&amp;nbsp;=&amp;nbsp;MaterialTheme.typography.titleMedium)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Spacer(Modifier.weight(1f))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;旋转图标动画
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;rotation&amp;nbsp;by&amp;nbsp;animateFloatAsState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(expanded)&amp;nbsp;180f&amp;nbsp;else&amp;nbsp;0f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;arrow_rotation&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Icon(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Icons.Default.KeyboardArrowDown,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;null,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.rotate(rotation)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedVisibility(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visible&amp;nbsp;=&amp;nbsp;expanded,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enter&amp;nbsp;=&amp;nbsp;expandVertically(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;spring(stiffness&amp;nbsp;=&amp;nbsp;Spring.StiffnessMediumLow)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;+&amp;nbsp;fadeIn(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;=&amp;nbsp;shrinkVertically()&amp;nbsp;+&amp;nbsp;fadeOut()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;content,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.padding(top&amp;nbsp;=&amp;nbsp;8.dp),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;style&amp;nbsp;=&amp;nbsp;MaterialTheme.typography.bodyMedium
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;&lt;code&gt;AnimatedContent&lt;/code&gt; 则用于内容变化时的过渡动画，比如数字跳动、页面切换：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;AnimatedCounter(count:&amp;nbsp;Int)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedContent(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetState&amp;nbsp;=&amp;nbsp;count,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transitionSpec&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;数字增加时从下往上滑入，减少时从上往下滑入
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(targetState&amp;nbsp;&amp;gt;&amp;nbsp;initialState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;slideInVertically&amp;nbsp;{&amp;nbsp;height&amp;nbsp;-&amp;gt;&amp;nbsp;height&amp;nbsp;}&amp;nbsp;+&amp;nbsp;fadeIn()&amp;nbsp;togetherWith
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;slideOutVertically&amp;nbsp;{&amp;nbsp;height&amp;nbsp;-&amp;gt;&amp;nbsp;-height&amp;nbsp;}&amp;nbsp;+&amp;nbsp;fadeOut()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;slideInVertically&amp;nbsp;{&amp;nbsp;height&amp;nbsp;-&amp;gt;&amp;nbsp;-height&amp;nbsp;}&amp;nbsp;+&amp;nbsp;fadeIn()&amp;nbsp;togetherWith
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;slideOutVertically&amp;nbsp;{&amp;nbsp;height&amp;nbsp;-&amp;gt;&amp;nbsp;height&amp;nbsp;}&amp;nbsp;+&amp;nbsp;fadeOut()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}.using(SizeTransform(clip&amp;nbsp;=&amp;nbsp;false))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;counter&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;targetCount&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;&amp;quot;$targetCount&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;style&amp;nbsp;=&amp;nbsp;MaterialTheme.typography.displayLarge
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;updateTransition：多属性联动动画&lt;/h2&gt;&lt;p&gt;当需要多个属性同步动画时，&lt;code&gt;updateTransition&lt;/code&gt; 是最佳选择。它可以确保所有属性动画保持时间同步：&lt;/p&gt;&lt;pre&gt;enum&amp;nbsp;class&amp;nbsp;ButtonState&amp;nbsp;{&amp;nbsp;Idle,&amp;nbsp;Pressed,&amp;nbsp;Loading,&amp;nbsp;Success&amp;nbsp;}

@Composable
fun&amp;nbsp;AnimatedActionButton(onClick:&amp;nbsp;()&amp;nbsp;-&amp;gt;&amp;nbsp;Unit)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;buttonState&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;mutableStateOf(ButtonState.Idle)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;transition&amp;nbsp;=&amp;nbsp;updateTransition(targetState&amp;nbsp;=&amp;nbsp;buttonState,&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;button_state&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;buttonWidth&amp;nbsp;by&amp;nbsp;transition.animateDp(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transitionSpec&amp;nbsp;=&amp;nbsp;{&amp;nbsp;spring(stiffness&amp;nbsp;=&amp;nbsp;Spring.StiffnessMedium)&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;width&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;state&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;(state)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Idle&amp;nbsp;-&amp;gt;&amp;nbsp;200.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Pressed&amp;nbsp;-&amp;gt;&amp;nbsp;190.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Loading&amp;nbsp;-&amp;gt;&amp;nbsp;56.dp&amp;nbsp;&amp;nbsp;//&amp;nbsp;收缩为圆形
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Success&amp;nbsp;-&amp;gt;&amp;nbsp;56.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;cornerRadius&amp;nbsp;by&amp;nbsp;transition.animateDp(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;corner_radius&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;state&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;(state)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Idle,&amp;nbsp;ButtonState.Pressed&amp;nbsp;-&amp;gt;&amp;nbsp;8.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Loading,&amp;nbsp;ButtonState.Success&amp;nbsp;-&amp;gt;&amp;nbsp;28.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;backgroundColor&amp;nbsp;by&amp;nbsp;transition.animateColor(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;bg_color&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;state&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;(state)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Idle&amp;nbsp;-&amp;gt;&amp;nbsp;MaterialTheme.colorScheme.primary
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Pressed&amp;nbsp;-&amp;gt;&amp;nbsp;MaterialTheme.colorScheme.primary.copy(alpha&amp;nbsp;=&amp;nbsp;0.8f)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Loading&amp;nbsp;-&amp;gt;&amp;nbsp;Color.Gray
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Success&amp;nbsp;-&amp;gt;&amp;nbsp;Color(0xFF4CAF50)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Box(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.width(buttonWidth)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.height(56.dp)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.clip(RoundedCornerShape(cornerRadius))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.background(backgroundColor)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.clickable&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(buttonState&amp;nbsp;==&amp;nbsp;ButtonState.Idle)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;buttonState&amp;nbsp;=&amp;nbsp;ButtonState.Pressed
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;模拟异步操作
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;buttonState&amp;nbsp;=&amp;nbsp;ButtonState.Loading
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentAlignment&amp;nbsp;=&amp;nbsp;Alignment.Center
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;(buttonState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Loading&amp;nbsp;-&amp;gt;&amp;nbsp;CircularProgressIndicator(color&amp;nbsp;=&amp;nbsp;Color.White,&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.size(24.dp))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ButtonState.Success&amp;nbsp;-&amp;gt;&amp;nbsp;Icon(Icons.Default.Check,&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;null,&amp;nbsp;tint&amp;nbsp;=&amp;nbsp;Color.White)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;-&amp;gt;&amp;nbsp;Text(&amp;quot;提交&amp;quot;,&amp;nbsp;color&amp;nbsp;=&amp;nbsp;Color.White)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;Animatable：手势驱动与精细控制&lt;/h2&gt;&lt;p&gt;当需要配合手势或实现复杂的交互动画时，&lt;code&gt;Animatable&lt;/code&gt; 提供了最底层的控制能力：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;SwipeableCard()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;offsetX&amp;nbsp;=&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;Animatable(0f)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;coroutineScope&amp;nbsp;=&amp;nbsp;rememberCoroutineScope()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Box(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.offset&amp;nbsp;{&amp;nbsp;IntOffset(offsetX.value.roundToInt(),&amp;nbsp;0)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.pointerInput(Unit)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detectHorizontalDragGestures(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onDragEnd&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;coroutineScope.launch&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;screenWidth&amp;nbsp;=&amp;nbsp;size.width
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.value&amp;nbsp;&amp;gt;&amp;nbsp;screenWidth&amp;nbsp;*&amp;nbsp;0.3f&amp;nbsp;-&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;划出右侧
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.animateTo(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;screenWidth.toFloat(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;tween(300)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.value&amp;nbsp;&amp;lt;&amp;nbsp;-screenWidth&amp;nbsp;*&amp;nbsp;0.3f&amp;nbsp;-&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;划出左侧
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.animateTo(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;-screenWidth.toFloat(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;tween(300)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;-&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;回弹
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.animateTo(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;0f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;spring(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dampingRatio&amp;nbsp;=&amp;nbsp;Spring.DampingRatioMediumBouncy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onHorizontalDrag&amp;nbsp;=&amp;nbsp;{&amp;nbsp;_,&amp;nbsp;dragAmount&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;coroutineScope.launch&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offsetX.snapTo(offsetX.value&amp;nbsp;+&amp;nbsp;dragAmount)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Card(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.size(300.dp,&amp;nbsp;200.dp)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;卡片内容
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;共享元素动画（Compose 1.7+）&lt;/h2&gt;&lt;p&gt;共享元素动画是提升导航体验的利器，Compose 1.7 正式引入了 &lt;code&gt;SharedTransitionLayout&lt;/code&gt;：&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;在&amp;nbsp;NavHost&amp;nbsp;中使用共享元素动画
@Composable
fun&amp;nbsp;AppNavigation()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;navController&amp;nbsp;=&amp;nbsp;rememberNavController()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SharedTransitionLayout&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NavHost(navController,&amp;nbsp;startDestination&amp;nbsp;=&amp;nbsp;&amp;quot;list&amp;quot;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;composable(&amp;quot;list&amp;quot;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedVisibilityScope&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(photos)&amp;nbsp;{&amp;nbsp;photo&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Image(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;painter&amp;nbsp;=&amp;nbsp;rememberAsyncImagePainter(photo.url),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;null,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.sharedElement(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state&amp;nbsp;=&amp;nbsp;rememberSharedContentState(key&amp;nbsp;=&amp;nbsp;&amp;quot;image_${photo.id}&amp;quot;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animatedVisibilityScope&amp;nbsp;=&amp;nbsp;this@composable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.clickable&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;navController.navigate(&amp;quot;detail/${photo.id}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;composable(&amp;quot;detail/{id}&amp;quot;)&amp;nbsp;{&amp;nbsp;backStackEntry&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;photoId&amp;nbsp;=&amp;nbsp;backStackEntry.arguments?.getString(&amp;quot;id&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Image(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;painter&amp;nbsp;=&amp;nbsp;rememberAsyncImagePainter(getPhoto(photoId).url),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;null,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.sharedElement(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state&amp;nbsp;=&amp;nbsp;rememberSharedContentState(key&amp;nbsp;=&amp;nbsp;&amp;quot;image_${photoId}&amp;quot;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animatedVisibilityScope&amp;nbsp;=&amp;nbsp;this@composable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.fillMaxWidth()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;性能优化：让动画不卡顿的关键技巧&lt;/h2&gt;&lt;p&gt;动画性能直接影响用户体验，以下是关键优化原则：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;优先动画 offset 和 alpha，避免触发重组&lt;/strong&gt;：使用 &lt;code&gt;Modifier.offset { }&lt;/code&gt;（lambda 版本）而非 &lt;code&gt;Modifier.offset(x, y)&lt;/code&gt;，前者在 Layout 阶段处理，不触发重组&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;使用 graphicsLayer 做 GPU 加速&lt;/strong&gt;：scale、rotation、alpha 等变换通过 &lt;code&gt;graphicsLayer&lt;/code&gt; 处理，完全在渲染线程执行，零重组开销&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;避免在动画过程中分配对象&lt;/strong&gt;：lambda 中避免创建新对象，确保每帧不触发 GC&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;合理使用 derivedStateOf&lt;/strong&gt;：当动画状态被多个组件读取时，用 &lt;code&gt;derivedStateOf&lt;/code&gt; 减少不必要的重组&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;✅&amp;nbsp;推荐：在&amp;nbsp;graphicsLayer&amp;nbsp;中做变换
Box(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.graphicsLayer&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaleX&amp;nbsp;=&amp;nbsp;scale
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaleY&amp;nbsp;=&amp;nbsp;scale
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alpha&amp;nbsp;=&amp;nbsp;alpha
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rotationZ&amp;nbsp;=&amp;nbsp;rotation
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
)

//&amp;nbsp;❌&amp;nbsp;避免：这些&amp;nbsp;modifier&amp;nbsp;会触发重组
Box(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.scale(scale)&amp;nbsp;&amp;nbsp;//&amp;nbsp;会触发重组
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.alpha(alpha)&amp;nbsp;&amp;nbsp;//&amp;nbsp;会触发重组
)&lt;/pre&gt;&lt;p&gt;通过 Android Studio 的 Layout Inspector 和 Composition Tracing 工具，可以可视化动画期间的重组次数，从而精准定位性能瓶颈。&lt;/p&gt;&lt;h2&gt;总结&lt;/h2&gt;&lt;p&gt;Jetpack Compose 的动画系统设计优雅，从简单的状态动画到复杂的手势交互，都有对应的 API 覆盖。掌握这套体系的关键在于：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;从高级 API 入手（&lt;code&gt;AnimatedVisibility&lt;/code&gt;、&lt;code&gt;AnimatedContent&lt;/code&gt;），快速实现大部分常见动画需求&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;多属性联动时使用 &lt;code&gt;updateTransition&lt;/code&gt;，保证时间同步&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;手势驱动或需要精细控制时使用 &lt;code&gt;Animatable&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;始终关注性能，优先选择不触发重组的动画方式&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Compose 1.7+ 的共享元素动画是导航体验升级的杀手级特性&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;动画是把双刃剑：恰到好处的动画让应用如虎添翼，过度的动画则会分散注意力、拖累性能。建议在设计动画时始终以用户体验为核心，遵循&amp;quot;有意义、可预测、响应迅速&amp;quot;的原则。&lt;/p&gt;</description><pubDate>Tue, 28 Jul 2026 08:05:39 +0800</pubDate></item></channel></rss>