<?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>LLM推理加速全攻略：KV Cache、投机采样与vLLM实战调优</title><link>https://blog.resmic.cn/post/377.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260907080522178873952222063.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;为什么LLM推理加速如此重要&lt;/h2&gt;&lt;p&gt;随着大型语言模型（LLM）在生产环境中的大规模部署，推理成本已成为AI产品商业化的核心瓶颈。以GPT-4级别的模型为例，单次请求的计算开销远超训练阶段的单步成本——自回归解码的串行性质导致GPU利用率低下，而用户对响应延迟的容忍度却越来越低。&lt;/p&gt;&lt;p&gt;根据业界实测数据，在未经优化的情况下，一张A100 GPU每秒仅能处理约10-20个token的生成请求。而通过系统性的推理优化，同等硬件可以将吞吐量提升5-10倍，将首token延迟（TTFT）降低60%以上。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&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;：首token延迟和整体响应速度影响产品竞争力&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;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;KV Cache：自回归推理的核心加速机制&lt;/h2&gt;&lt;p&gt;KV Cache（键值缓存）是Transformer推理加速中最基础也最重要的技术。在自回归生成过程中，每生成一个新token，模型需要对所有历史token重新计算注意力。KV Cache的核心思路是将已计算过的Key和Value矩阵缓存下来，避免重复计算。&lt;/p&gt;&lt;p&gt;KV Cache的主要挑战在于显存占用。对于一个70B参数的模型，单个请求的KV Cache可能占用数GB显存，这限制了并发请求数量。为此，业界提出了多种优化方案：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Query Attention (MQA)&lt;/strong&gt;：所有Query头共享一组KV，显存减少约8倍，代价是轻微的精度损失&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Grouped-Query Attention (GQA)&lt;/strong&gt;：将Query头分组共享KV，在精度和效率间取得更好平衡，Llama 3采用了此方案&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;PagedAttention&lt;/strong&gt;：vLLM提出的分页管理机制，将KV Cache分割成固定大小的物理块动态分配，可将显存碎片降至5%以下&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sliding Window Attention&lt;/strong&gt;：Mistral采用的局部注意力机制，只保留最近N个token的KV，适合长序列场景&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;PagedAttention的核心思想借鉴了操作系统的虚拟内存管理：为每个请求维护一个逻辑KV块到物理KV块的映射表（Block Table）。物理块可以在不同请求间复用，当前缀相同时甚至可以共享（Prefix Caching），这对RAG场景下的重复system prompt有显著加速效果。&lt;/p&gt;&lt;h2&gt;投机采样：用小模型加速大模型解码&lt;/h2&gt;&lt;p&gt;投机采样（Speculative Decoding）是近年来最具创意的LLM推理加速技术之一。其核心思想是：用一个小型草稿模型（Draft Model）先快速生成多个候选token，然后用大型目标模型（Target Model）并行验证，被接受的token直接采用，被拒绝的token重新采样。&lt;/p&gt;&lt;p&gt;这一方法的神奇之处在于：并行验证多个token的计算成本与验证单个token几乎相同（因为Transformer天然支持并行前向传播），而成功接受多个token则意味着单次前向传播完成了多步解码。投机采样在数学上可以被证明与原始模型的采样分布完全等价，不会改变输出质量。&lt;/p&gt;&lt;p&gt;实践中，投机采样的加速比取决于草稿模型的接受率。当接受率达到80%以上时，理论加速比可达3-4倍。主流实现方案包括：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Medusa&lt;/strong&gt;：在原模型的最后隐层上添加多个并行解码头（Medusa heads），无需单独草稿模型，部署更简单&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;EAGLE&lt;/strong&gt;：利用特征级别对齐提升草稿准确率，相比Medusa进一步提高接受率&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;SpecInfer&lt;/strong&gt;：支持树形投机结构（Tree Attention），同时验证多条候选路径，最大化GPU利用率&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lookahead Decoding&lt;/strong&gt;：不需要草稿模型，通过n-gram缓存猜测未来token，适合无法修改模型的场景&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;连续批处理与动态调度&lt;/h2&gt;&lt;p&gt;传统的静态批处理（Static Batching）要求一批请求同时开始、同时结束，而实际场景中不同请求的生成长度差异极大，短请求的GPU必须空等长请求完成，造成严重的计算资源浪费——GPU利用率有时低至20-30%。&lt;/p&gt;&lt;p&gt;连续批处理（Continuous Batching，也称 Iteration-level Batching）的核心思想是：以迭代步（iteration step）而非请求为单位进行批处理调度。每次迭代完成后，系统立即将已结束的请求移出批次，并补入等待队列中的新请求。&lt;/p&gt;&lt;p&gt;连续批处理配合PagedAttention，是vLLM实现高吞吐量的核心架构。在高并发场景下，相比朴素实现可提升吞吐量10-20倍。调度器需要关注以下关键参数：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;max_num_seqs&lt;/strong&gt;：最大并发请求数，受KV Cache显存容量限制&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;max_num_batched_tokens&lt;/strong&gt;：单次迭代最大token数，影响GPU利用率和响应延迟之间的权衡&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;chunked prefill&lt;/strong&gt;：将长prefill拆分成多个chunk，避免长prefill阻塞decode，降低P99延迟&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;抢占式调度&lt;/strong&gt;：当KV Cache耗尽时，可以将低优先级请求的KV Cache换出到CPU内存（swap），保障高优先级请求的服务质量&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;量化推理：从FP16到INT4的精度-效率权衡&lt;/h2&gt;&lt;p&gt;量化是在不显著损失模型精度的前提下，将模型参数从高精度（FP32/FP16）压缩为低精度（INT8/INT4）的技术。对于LLM推理而言，量化的收益是双重的：显存占用减少、计算吞吐提升。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPTQ&lt;/strong&gt;：Post-Training Quantization，基于二阶梯度信息（Hessian矩阵）的层级量化，INT4精度损失极小，是目前最广泛使用的离线量化方案&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWQ（Activation-aware Weight Quantization）&lt;/strong&gt;：通过分析激活分布，识别并保护对模型性能最关键的1%权重，INT4量化后精度接近FP16基线&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;SmoothQuant&lt;/strong&gt;：将激活值的量化难度通过数学变换迁移到权重上，实现W8A8（权重INT8+激活INT8）量化，推理速度提升约1.5倍&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GGUF/llama.cpp&lt;/strong&gt;：面向CPU和消费级GPU推理的混合精度量化格式，支持Q4_K_M、Q5_K_M等精细化方案，在MacBook Pro上可运行7B模型&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;实测数据表明，AWQ INT4量化的70B模型在单张A100（80GB）上即可部署，推理速度比FP16快2-3倍，而在主流benchmark（MMLU、HellaSwag等）上的精度损失通常低于1%。&lt;/p&gt;&lt;h2&gt;vLLM生产部署关键配置&lt;/h2&gt;&lt;p&gt;vLLM是目前生产环境中最广泛使用的LLM推理框架，集成了PagedAttention、连续批处理、张量并行等核心优化技术，并提供OpenAI兼容的API接口，便于迁移现有应用。&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;tensor-parallel-size&lt;/strong&gt;：张量并行GPU数量，单机多卡场景优先使用TP而非PP（Pipeline Parallelism）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;gpu-memory-utilization&lt;/strong&gt;：GPU显存使用率上限，建议设为0.85-0.92，为CUDA碎片和运行时开销留出空间&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;max-num-batched-tokens&lt;/strong&gt;：控制prefill阶段的最大token数，值越大吞吐越高但TTFT越长&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;enable-chunked-prefill&lt;/strong&gt;：开启后将长prefill拆分执行，有效降低decode延迟的抖动&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;enforce-eager&lt;/strong&gt;：禁用CUDA Graph捕获，调试时使用；生产环境关闭以获得10-15%的额外加速&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;监控指标建议：重点关注GPU KV Cache利用率（目标80-90%）、请求队列长度（应接近0）、token生成吞吐量（tokens/s）以及各百分位延迟（P50/P95/P99 TTFT和E2E latency）。&lt;/p&gt;&lt;h2&gt;Flash Attention与算子级优化&lt;/h2&gt;&lt;p&gt;Flash Attention是由Tri Dao等人提出的一种IO感知的精确注意力算法。传统注意力计算需要将整个N×N注意力矩阵写入HBM（高带宽显存），而Flash Attention通过将计算分块（tiling）并在SRAM中完成，将注意力计算的HBM访问量从O(N²)降至O(N)，速度提升2-4倍，显存节省更为显著。&lt;/p&gt;&lt;p&gt;Flash Attention 2相较v1进一步优化了并行化策略和warp内的计算分配，在A100上可达到约70%的理论算力峰值。Flash Attention 3针对H100的新特性（Tensor Core异步计算、FP8支持）做了专项优化。&lt;/p&gt;&lt;p&gt;除Flash Attention外，以下算子级优化同样值得关注：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fused Kernels&lt;/strong&gt;：将RMSNorm、SwiGLU激活、Rotary Position Embedding等多个连续算子融合为单一CUDA kernel，减少HBM读写次数&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;CUDA Graph&lt;/strong&gt;：将固定形状的推理计算图（decode阶段token形状固定）捕获为CUDA Graph，消除动态kernel调度开销，可降低10-15%延迟&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Triton自定义算子&lt;/strong&gt;：针对特定硬件手写OpenAI Triton kernel，在特定算子上可超越cuBLAS/cuDNN通用实现&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;TensorRT-LLM&lt;/strong&gt;：NVIDIA官方推理优化框架，通过层融合、精度校准、kernel autotuning等技术，在A100/H100上通常比vLLM快20-30%，但工程复杂度更高&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;性能基准与选型建议&lt;/h2&gt;&lt;p&gt;在实际工程选型时，以下基准数据可供参考（测试环境：8×A100 80GB SXM，Llama-3-70B-Instruct，输入512 tokens，输出256 tokens，并发32）：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;朴素FP16推理（HuggingFace原生）&lt;/strong&gt;：吞吐约1,200 tokens/s，TTFT约1.2s&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;vLLM + PagedAttention&lt;/strong&gt;：吞吐约8,500 tokens/s（7倍提升），TTFT约0.3s&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;vLLM + AWQ INT4 + Flash Attention 2&lt;/strong&gt;：并发64时吞吐约15,000 tokens/s，显存占用减半&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;vLLM + 投机采样（Medusa）&lt;/strong&gt;：单请求延迟降低约40%，批量吞吐提升约1.5倍&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;TensorRT-LLM&lt;/strong&gt;：在H100上通常比vLLM再快30-50%，但需要针对每个模型重新构建engine&lt;/p&gt;&lt;/li&gt;&lt;/ul&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;vLLM&lt;/strong&gt;（首选）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;极致吞吐、NVIDIA专有硬件、愿意投入工程资源 → &lt;strong&gt;TensorRT-LLM&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;CPU或消费级GPU本地推理 → &lt;strong&gt;llama.cpp + GGUF量化&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;移动端和边缘设备 → &lt;strong&gt;MLC-LLM + INT4量化&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;SGLang值得重点关注：其RadixAttention和结构化输出支持在推理框架中独树一帜，特别适合RAG和Function Calling场景&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;LLM推理优化是一个快速演进的领域，建议工程师持续关注vLLM、SGLang、Lmdeploy等开源项目的最新动态，根据实际业务负载特征（在线vs离线、延迟敏感vs吞吐优先、模型大小）选择最适合的优化组合。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 07 Sep 2026 08:10:41 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：属性钩子、懒对象与数组函数实战指南</title><link>https://blog.resmic.cn/post/376.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260906080731178865325136616.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 月正式发布，带来了多项重要改进。&lt;/p&gt;&lt;h2&gt;属性钩子&lt;/h2&gt;&lt;p&gt;属性钩子允许为类属性定义 get 和 set 逻辑，简化代码结构。&lt;/p&gt;&lt;h2&gt;数组函数&lt;/h2&gt;&lt;p&gt;新增 array_find、array_find_key、array_any、array_all 四个实用函数。&lt;/p&gt;&lt;h2&gt;懒对象&lt;/h2&gt;&lt;p&gt;通过反射 API 支持懒加载对象，提升性能。&lt;/p&gt;&lt;h2&gt;升级建议&lt;/h2&gt;&lt;p&gt;建议使用 Rector 工具辅助迁移，升级前做好测试。&lt;/p&gt;</description><pubDate>Sun, 06 Sep 2026 08:19:41 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：Property Hooks、Lazy Objects 等实战指南</title><link>https://blog.resmic.cn/post/375.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260905080349178856662927726.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，是近年来最具里程碑意义的版本之一。这一版本带来了语言层面的重大革新，包括 Property Hooks 属性钩子、Lazy Objects 懒加载对象、全新的数组函数族、无括号 new 链式调用以及原生的废弃标注系统。本文将逐一深入解析这些新特性，帮助开发者在项目中快速落地应用。&lt;/p&gt;&lt;h2&gt;一、Property Hooks：终结冗长的 Getter/Setter 时代&lt;/h2&gt;&lt;p&gt;Property Hooks 是 PHP 8.4 最受关注的特性之一，也是语言设计层面最深刻的一次变革。在此之前，PHP 开发者不得不为每个需要访问控制的属性单独编写 getter 和 setter 方法，这导致了大量模板化代码的堆积，尤其在 DTO、值对象和领域模型中尤为明显。&lt;/p&gt;&lt;p&gt;Property Hooks 允许开发者在属性声明处直接内联 get 和 set 逻辑。get 钩子在读取属性时触发，可以对原始值进行转换后返回；set 钩子在赋值时触发，可以验证值的合法性并在存储前进行格式化处理。两个钩子都是可选的，可以单独使用 get 或 set，也可以同时定义。&lt;/p&gt;&lt;p&gt;Property Hooks 同样支持接口定义。接口中可以声明带钩子约束的属性签名，实现类必须满足对应的读写访问要求。这一能力在 API 设计和依赖注入场景中极为强大，可以在接口层面精确控制属性的暴露粒度。Hooks 还支持继承和覆写，子类可以扩展或收窄父类属性的访问行为。&lt;/p&gt;&lt;p&gt;从实际使用角度来看，Property Hooks 最适合以下场景：需要对输入值进行清洗或规范化的属性（如 email 自动 trim + 转小写）、需要延迟计算的只读属性、以及需要在赋值时触发副作用的属性（如记录修改历史）。对于纯数据容器类，简单属性不需要 Hooks，直接使用 public 属性或构造器提升（Constructor Promotion）即可保持简洁。&lt;/p&gt;&lt;h2&gt;二、Lazy Objects：按需初始化的性能利器&lt;/h2&gt;&lt;p&gt;Lazy Objects（懒加载对象）解决了一个长期存在的架构痛点：在依赖注入容器或 ORM 中，某些对象可能永远不会被使用，但实例化时仍然要执行完整的构造逻辑，造成不必要的性能开销。&lt;/p&gt;&lt;p&gt;PHP 8.4 通过 ReflectionClass 的两个新方法引入了懒加载能力。newLazyGhost 创建一个&amp;quot;幽灵&amp;quot;对象，它看起来和用起来都与真实对象完全相同，但构造函数不会立即执行；只有当第一次访问对象的属性或方法时，初始化回调才会被触发，完成真正的构造逻辑。newLazyProxy 则创建一个代理对象，它内部持有一个真实对象，所有属性和方法访问都会透明地转发到真实对象上。&lt;/p&gt;&lt;p&gt;两种模式各有适用场景。Lazy Ghost 适合你可以访问和修改目标类的情况，对象标识保持一致，is_a 和 instanceof 检查都能正确通过；Lazy Proxy 更适合无法修改的第三方类，或者需要在初始化时替换不同实现的场景。无论哪种模式，标记某个属性为&amp;quot;跳过懒加载初始化&amp;quot;都是支持的，这对于需要在初始化前就能访问的元数据属性非常有用。&lt;/p&gt;&lt;p&gt;在实际框架集成中，Lazy Objects 将极大简化依赖注入容器的代理对象生成逻辑。目前 Symfony、Laravel 等主流框架都已开始适配这一特性，未来将成为容器性能优化的标准工具。&lt;/p&gt;&lt;h2&gt;三、全新数组函数族：array_find、array_any、array_all&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了四个期待已久的数组处理函数，彻底填补了标准库在集合操作方面的空白，不再需要通过 array_filter + reset 的组合变通来实现简单的查找逻辑。&lt;/p&gt;&lt;p&gt;array_find 接受一个数组和一个回调函数，返回数组中第一个使回调返回真值的元素；如果没有匹配则返回 null。与 array_filter 的关键区别在于：array_find 找到第一个匹配项后立即短路退出，不会遍历整个数组，在大型数据集上性能显著更优。array_find_key 与之类似，但返回的是匹配元素的键名而不是元素本身。&lt;/p&gt;&lt;p&gt;array_any 检查数组中是否至少存在一个元素满足给定条件，返回布尔值。同样在找到第一个匹配时短路。array_all 检查数组中是否所有元素都满足条件，找到第一个不满足的元素时即短路退出。这四个函数配合箭头函数语法，让集合操作代码变得更加声明式和表达力强。&lt;/p&gt;&lt;p&gt;值得注意的是，这些函数遵循 PHP 的&amp;quot;一致性&amp;quot;设计原则：回调函数签名为 function(mixed $value, mixed $key): bool，同时接收值和键作为参数，这与 array_filter 保持一致，方便开发者迁移既有代码。&lt;/p&gt;&lt;h2&gt;四、无括号 new 表达式：链式调用更自然&lt;/h2&gt;&lt;p&gt;这是一个期待了很久的语法糖改进。在 PHP 8.4 之前，如果想在 new 创建对象后立即调用方法，必须用括号包裹整个 new 表达式，例如 (new Builder())-&amp;gt;build()。这种写法既不美观，也让链式调用变得笨拙，尤其在构建 DSL（领域特定语言）风格的 API 时颇为影响可读性。&lt;/p&gt;&lt;p&gt;PHP 8.4 移除了这一限制，现在可以直接在 new 表达式后接 -&amp;gt; 调用方法，而无需额外的括号包裹。这使得流畅接口（Fluent Interface）模式的代码变得更加自然，查询构建器、配置构建器、测试断言等场景都会受益。&lt;/p&gt;&lt;p&gt;这一变更完全向后兼容，旧的括号写法依然有效。值得一提的是，静态属性和常量访问 new Foo()::CONSTANT 也同样支持，不再受到语法限制。&lt;/p&gt;&lt;h2&gt;五、新 HTML5 解析器：告别 libxml 的历史包袱&lt;/h2&gt;&lt;p&gt;PHP 的 DOM 扩展自 PHP 5 时代就依赖 libxml 解析 HTML，但 libxml 是为 XML 设计的，对现代 HTML5 文档的解析存在诸多已知缺陷：不支持 HTML5 自定义元素、实体处理不完整、容错能力有限，导致许多开发者不得不转向第三方库。&lt;/p&gt;&lt;p&gt;PHP 8.4 引入了全新的 Dom\HTMLDocument 类，底层使用 Lexbor 库，这是一个完整实现 HTML5 规范的高性能解析器。新解析器支持所有 HTML5 语义化标签、正确处理 HTML5 实体、具备与浏览器一致的容错行为，以及完整的 Unicode 支持。&lt;/p&gt;&lt;p&gt;更重要的是，新的 Dom\HTMLDocument 和 Dom\XMLDocument 增加了 querySelector 和 querySelectorAll 方法，开发者终于可以用熟悉的 CSS 选择器语法查询 DOM 元素，告别了冗长的 getElementsByTagName 和 XPath 表达式。同时，新 API 支持更简洁的序列化方法，以及对 Unicode 不规范字符的严格处理选项，非常适合内容抓取和 HTML 转换场景。&lt;/p&gt;&lt;h2&gt;六、内置废弃标注系统&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了 #[Deprecated] attribute，为语言提供了原生的废弃（Deprecation）标注能力。在此之前，PHP 核心函数的废弃通过引擎内部硬编码实现，而第三方代码中的废弃只能通过 trigger_error 函数手动触发，这种方式不够优雅，也无法被 IDE 和静态分析工具有效识别。&lt;/p&gt;&lt;p&gt;新的 #[Deprecated] attribute 可以应用于函数、方法和类常量。它接受两个可选参数：message 用于描述废弃原因和替代方案，since 用于记录废弃引入的版本号。当被标注的函数或方法被调用时，PHP 引擎会自动触发 E_USER_DEPRECATED 级别的警告，警告信息中会包含 message 和 since 的内容，让调用方明确了解迁移方向。&lt;/p&gt;&lt;p&gt;这一特性对框架和库维护者意义重大。统一的废弃标注系统让 IDE 插件、PHPStan、Psalm 等工具能够在静态分析阶段就识别废弃调用，帮助团队在升级框架时提前发现兼容性问题，大幅降低迁移风险。&lt;/p&gt;&lt;h2&gt;七、升级实战：从 PHP 8.3 迁移到 8.4&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;隐式可空类型参数已废弃：过去 function foo(string $x = null) 是合法的，PHP 会隐式将 string 扩展为 string|null。从 8.4 开始这会产生废弃警告，需要显式写成 function foo(string|null $x = null)。建议通过 PHPStan level 6 或更高级别提前扫描代码库。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;GMP 和 Bcmath 扩展行为变更：部分函数在处理边界值时行为有所调整，升级前务必查阅官方迁移指南 migrate84。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;DOM 扩展类层次变化：新增的 Dom\ 命名空间类与旧版 DOMDocument 共存，但部分继承关系有调整，如果项目中有 DOM 相关的类型声明需要逐一检查。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;推荐的升级策略是分阶段推进：首先在本地开发环境切换到 PHP 8.4，运行完整测试套件并修复所有废弃警告；然后将修复推送到预发布环境，观察 1-2 周的运行状况；确认稳定后再推进到生产环境。对于大型项目，可以借助 Rector 工具自动化处理部分代码迁移工作，特别是隐式可空类型的批量修复。&lt;/p&gt;&lt;p&gt;总体而言，PHP 8.4 是一次在语言表达力和运行时性能上都有实质提升的版本。早日迁移，即可享受更优雅的代码风格和更高效的运行时特性。&lt;/p&gt;</description><pubDate>Sat, 05 Sep 2026 08:08:13 +0800</pubDate></item><item><title>PHP 8.3 新特性深度解析：类型化常量、json_validate 与 Override 注解</title><link>https://blog.resmic.cn/post/374.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260904080713178848043391514.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;PHP 8.3 新特性概览&lt;/h2&gt;&lt;p&gt;PHP 8.3 于 2023 年 11 月正式发布，延续了 PHP 8.x 系列持续演进的势头，在类型系统、性能优化和标准库方面均有显著提升。对于生产环境中仍在使用 PHP 7.x 的团队而言，现在正是规划升级路线的好时机。本文将逐一解析 PHP 8.3 中最值得关注的几大新特性，并附上完整可运行的代码示例。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;类型化类常量（Typed Class Constants）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;只读类（Readonly Classes）增强&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增 &lt;code&gt;json_validate()&lt;/code&gt; 函数&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Override&lt;/code&gt; 属性注解&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Fibers 与异步改进&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;类型化类常量&lt;/h2&gt;&lt;p&gt;在 PHP 8.3 之前，类常量没有类型约束，任何值都可以赋给常量，这在大型项目中容易引发难以追踪的类型错误。PHP 8.3 引入了类型化类常量，让开发者可以为常量声明明确的类型。&lt;/p&gt;&lt;p&gt;&lt;em&gt;[php代码示例 - 见下方文字描述]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;类型化常量支持所有标量类型（&lt;code&gt;string&lt;/code&gt;、&lt;code&gt;int&lt;/code&gt;、&lt;code&gt;float&lt;/code&gt;、&lt;code&gt;bool&lt;/code&gt;）以及 &lt;code&gt;array&lt;/code&gt;，同时也支持类类型和接口类型。这一特性使 API 合约更加严格，有效减少了因常量类型不匹配导致的潜在 Bug。&lt;/p&gt;&lt;h2&gt;json_validate() 函数&lt;/h2&gt;&lt;p&gt;在 PHP 8.3 之前，验证一个字符串是否为合法 JSON 通常需要先调用 &lt;code&gt;json_decode()&lt;/code&gt; 再检查 &lt;code&gt;json_last_error()&lt;/code&gt;，不仅浪费内存，还需要分配完整的数据结构。PHP 8.3 新增的 &lt;code&gt;json_validate()&lt;/code&gt; 函数解决了这个问题。&lt;/p&gt;&lt;p&gt;&lt;em&gt;[php代码示例 - 见下方文字描述]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;性能测试表明，对于大型 JSON 字符串，&lt;code&gt;json_validate()&lt;/code&gt; 的速度比 &lt;code&gt;json_decode()&lt;/code&gt; 快约 2 倍，内存占用减少约 50%。&lt;/p&gt;&lt;h2&gt;#[Override] 属性注解&lt;/h2&gt;&lt;p&gt;PHP 8.3 引入了 &lt;code&gt;#[Override]&lt;/code&gt; 属性，用于标记一个方法确实是在覆盖父类或接口中的方法。这在重构代码或修改类层次结构时特别有用，能够防止因拼写错误或接口变更导致的静默失效。&lt;/p&gt;&lt;p&gt;&lt;em&gt;[php代码示例 - 见下方文字描述]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;有了 &lt;code&gt;#[Override]&lt;/code&gt;，当父类方法被重命名或删除时，子类会立即抛出致命错误，而不是悄悄地变成一个无效的新方法。这对维护大型继承体系的项目来说是一个重要的安全网。&lt;/p&gt;&lt;h2&gt;升级建议与兼容性注意事项&lt;/h2&gt;&lt;p&gt;从旧版 PHP 升级到 8.3 时，需要关注以下几个潜在的不兼容变更：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;弃用动态属性：&lt;/strong&gt; PHP 8.2 开始弃用未声明的动态属性，8.3 中继续收紧。建议为所有属性添加显式声明或使用 &lt;code&gt;#[AllowDynamicProperties]&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;mt_rand() 行为变化：&lt;/strong&gt; 随机数生成逻辑有细微调整，依赖固定随机序列的测试可能需要更新。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symfony / Laravel 支持：&lt;/strong&gt; Laravel 10+ 和 Symfony 6.3+ 均已原生支持 PHP 8.3，可以放心升级。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;扩展兼容性：&lt;/strong&gt; 升级前务必检查项目依赖的 PECL 扩展是否已有 PHP 8.3 版本。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;[bash代码示例 - 见下方文字描述]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;总体而言，PHP 8.3 是一次值得期待的版本升级。新增的类型化常量和 &lt;code&gt;#[Override]&lt;/code&gt; 注解让代码更健壮，&lt;code&gt;json_validate()&lt;/code&gt; 则在高频 API 场景下带来了可观的性能收益。建议开发团队在充分测试后，尽快将生产环境迁移至 PHP 8.3，以享受这些改进带来的红利。&lt;/p&gt;</description><pubDate>Fri, 04 Sep 2026 08:10:11 +0800</pubDate></item><item><title>Jetpack Compose高级动画实战：从物理动画到共享元素过渡</title><link>https://blog.resmic.cn/post/373.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260903080419178839385980056.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;p&gt;Jetpack Compose 的动画系统是 Android UI 开发中最令人兴奋的特性之一。随着 Compose 逐渐成为 Android 开发的主流方案，掌握其高级动画技术已成为提升应用品质的关键。本文将带你深入了解 Compose 动画系统的进阶用法，从状态过渡到物理动画，全面提升你的动画开发能力。&lt;/p&gt;&lt;h2&gt;一、AnimatedContent：优雅处理内容切换&lt;/h2&gt;&lt;p&gt;&lt;code&gt;AnimatedContent&lt;/code&gt; 是 Compose 中处理内容切换动画的利器。与简单的 &lt;code&gt;AnimatedVisibility&lt;/code&gt; 相比，它能够在不同内容之间实现平滑的过渡效果，特别适合处理数据加载状态、Tab 切换等场景。&lt;/p&gt;&lt;p&gt;基本用法示例：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;ContentSwitcher(targetState:&amp;nbsp;UiState)&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;targetState,
&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;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;targetState&amp;nbsp;is&amp;nbsp;UiState.Success&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;initialState&amp;nbsp;is&amp;nbsp;UiState.Loading&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;fadeIn(tween(300))&amp;nbsp;+&amp;nbsp;slideInVertically&amp;nbsp;{&amp;nbsp;it&amp;nbsp;/&amp;nbsp;2&amp;nbsp;}&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;fadeOut(tween(150))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;fadeIn(tween(200))&amp;nbsp;togetherWith&amp;nbsp;fadeOut(tween(200))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;ContentTransition&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;is&amp;nbsp;UiState.Loading&amp;nbsp;-&amp;gt;&amp;nbsp;LoadingScreen()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;is&amp;nbsp;UiState.Success&amp;nbsp;-&amp;gt;&amp;nbsp;SuccessContent(state.data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;is&amp;nbsp;UiState.Error&amp;nbsp;-&amp;gt;&amp;nbsp;ErrorScreen(state.message)
&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;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;transitionSpec&lt;/code&gt; 针对不同状态切换定制不同动画&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;togetherWith&lt;/code&gt;（原 &lt;code&gt;with&lt;/code&gt;）用于组合进入和退出动画&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;始终设置 &lt;code&gt;label&lt;/code&gt; 参数，便于 Animation Inspector 调试&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;利用 &lt;code&gt;SizeTransform&lt;/code&gt; 控制内容大小变化的动画方式&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;二、共享元素过渡：跨页面的视觉连续性&lt;/h2&gt;&lt;p&gt;Compose 1.7 正式引入了稳定的共享元素过渡 API（&lt;code&gt;SharedTransitionLayout&lt;/code&gt;），让列表到详情的过渡动画变得前所未有的简单。&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;ListScreen(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items:&amp;nbsp;List,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onItemClick:&amp;nbsp;(Item)&amp;nbsp;-&amp;gt;&amp;nbsp;Unit,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animatedVisibilityScope:&amp;nbsp;AnimatedVisibilityScope,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sharedTransitionScope:&amp;nbsp;SharedTransitionScope
)&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;items(items)&amp;nbsp;{&amp;nbsp;item&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;with(sharedTransitionScope)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;.clickable&amp;nbsp;{&amp;nbsp;onItemClick(item)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.sharedBounds(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rememberSharedContentState(key&amp;nbsp;=&amp;nbsp;&amp;quot;container-${item.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;animatedVisibilityScope&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resizeMode&amp;nbsp;=&amp;nbsp;SharedTransitionScope.ResizeMode.ScaleToBounds()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;painter&amp;nbsp;=&amp;nbsp;rememberAsyncImagePainter(item.imageUrl),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;modifier&amp;nbsp;=&amp;nbsp;Modifier.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;rememberSharedContentState(key&amp;nbsp;=&amp;nbsp;&amp;quot;image-${item.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;animatedVisibilityScope&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;item.title,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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.sharedBounds(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rememberSharedContentState(key&amp;nbsp;=&amp;nbsp;&amp;quot;title-${item.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;animatedVisibilityScope&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&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;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;sharedElement&lt;/code&gt; 用于完全相同的元素（如图片），&lt;code&gt;sharedBounds&lt;/code&gt; 用于可变大小的容器&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;NavHost&lt;/code&gt; 时，通过 &lt;code&gt;rememberAnimatedNavController&lt;/code&gt; 传递动画作用域&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;为复杂列表设置 &lt;code&gt;skipToLookaheadSize&lt;/code&gt; 避免布局抖动&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对文本使用 &lt;code&gt;OverlayClip&lt;/code&gt; 防止过渡期间内容溢出&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;三、基于物理的动画：Spring 与 Decay&lt;/h2&gt;&lt;p&gt;物理动画能让 UI 交互感觉更加自然真实。Compose 提供了 &lt;code&gt;spring()&lt;/code&gt; 和 &lt;code&gt;exponentialDecay()&lt;/code&gt; 两种主要的物理动画规格。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;Spring&amp;nbsp;动画&amp;nbsp;-&amp;nbsp;模拟弹簧物理
val&amp;nbsp;springSpec&amp;nbsp;=&amp;nbsp;spring(
&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;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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;刚度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visibilityThreshold&amp;nbsp;=&amp;nbsp;0.001f
)

//&amp;nbsp;在手势释放后使用&amp;nbsp;spring&amp;nbsp;恢复
@Composable
fun&amp;nbsp;DraggableCard()&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;
&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.draggable(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;orientation&amp;nbsp;=&amp;nbsp;Orientation.Horizontal,
&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;rememberDraggableState&amp;nbsp;{&amp;nbsp;delta&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;LaunchedEffect(delta)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;delta)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onDragStopped&amp;nbsp;=&amp;nbsp;{&amp;nbsp;velocity&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;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;&amp;nbsp;&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;(abs(offsetX.value)&amp;nbsp;&amp;gt;&amp;nbsp;200f)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;targetValue&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(offsetX.value&amp;nbsp;&amp;gt;&amp;nbsp;0)&amp;nbsp;1000f&amp;nbsp;else&amp;nbsp;-1000f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;easing&amp;nbsp;=&amp;nbsp;FastOutLinearInEasing)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&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;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;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;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;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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;initialVelocity&amp;nbsp;=&amp;nbsp;velocity
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;)
}&lt;/pre&gt;&lt;p&gt;Spring 参数调优建议：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;DampingRatioNoBouncy (1.0)&lt;/code&gt;：用于功能性动画，无弹跳&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;DampingRatioLowBouncy (0.75)&lt;/code&gt;：轻微弹跳，适合卡片展开&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;DampingRatioMediumBouncy (0.5)&lt;/code&gt;：明显弹跳，适合游戏类交互&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;DampingRatioHighBouncy (0.2)&lt;/code&gt;：强烈弹跳，谨慎使用&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;四、自定义 Easing 与 AnimationSpec&lt;/h2&gt;&lt;p&gt;标准的缓动函数往往无法满足特定设计需求，Compose 支持通过 &lt;code&gt;CubicBezierEasing&lt;/code&gt; 自定义缓动曲线，以及通过 &lt;code&gt;KeyframesSpec&lt;/code&gt; 创建关键帧动画。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;自定义贝塞尔缓动
val&amp;nbsp;emphasizedEasing&amp;nbsp;=&amp;nbsp;CubicBezierEasing(0.2f,&amp;nbsp;0.0f,&amp;nbsp;0.0f,&amp;nbsp;1.0f)&amp;nbsp;&amp;nbsp;//&amp;nbsp;Material&amp;nbsp;You&amp;nbsp;emphasized
val&amp;nbsp;emphasizedDecelerateEasing&amp;nbsp;=&amp;nbsp;CubicBezierEasing(0.05f,&amp;nbsp;0.7f,&amp;nbsp;0.1f,&amp;nbsp;1.0f)

//&amp;nbsp;关键帧动画&amp;nbsp;-&amp;nbsp;精确控制动画时间线
val&amp;nbsp;bounceSpec&amp;nbsp;=&amp;nbsp;keyframes{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;durationMillis&amp;nbsp;=&amp;nbsp;1000
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0f&amp;nbsp;at&amp;nbsp;0&amp;nbsp;with&amp;nbsp;FastOutSlowInEasing
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.2f&amp;nbsp;at&amp;nbsp;600&amp;nbsp;with&amp;nbsp;FastOutSlowInEasing&amp;nbsp;&amp;nbsp;//&amp;nbsp;超出目标值产生弹跳效果
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0.9f&amp;nbsp;at&amp;nbsp;750
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.05f&amp;nbsp;at&amp;nbsp;850
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.0f&amp;nbsp;at&amp;nbsp;1000
}

//&amp;nbsp;组合多个动画规格
@Composable
fun&amp;nbsp;AnimatedButton(onClick:&amp;nbsp;()&amp;nbsp;-&amp;gt;&amp;nbsp;Unit)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;scale&amp;nbsp;=&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;Animatable(1f)&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;.scale(scale.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;.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;interactionSource&amp;nbsp;=&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;MutableInteractionSource()&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;indication&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;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;scale.animateTo(0.9f,&amp;nbsp;tween(100))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scale.animateTo(1f,&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;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;onClick()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;KeyframesSpec 进阶技巧：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;at&lt;/code&gt; infix 函数指定关键帧时间点&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;with&lt;/code&gt; infix 函数为每段指定缓动&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;atFraction&lt;/code&gt; 用于按比例而非绝对时间定义关键帧&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;结合 &lt;code&gt;repeatable&lt;/code&gt; 创建循环关键帧动画&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;五、Transition API：多属性协同动画&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;BoxState&amp;nbsp;{&amp;nbsp;Collapsed,&amp;nbsp;Expanded&amp;nbsp;}

@Composable
fun&amp;nbsp;AnimatedBox()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;currentState&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;mutableStateOf(BoxState.Collapsed)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;transition&amp;nbsp;=&amp;nbsp;updateTransition(currentState,&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;BoxTransition&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;size&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;&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;BoxState.Collapsed&amp;nbsp;isTransitioningTo&amp;nbsp;BoxState.Expanded&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;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;else&amp;nbsp;-&amp;gt;&amp;nbsp;tween(200)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;BoxSize&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;BoxState.Collapsed&amp;nbsp;-&amp;gt;&amp;nbsp;64.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;BoxState.Expanded&amp;nbsp;-&amp;gt;&amp;nbsp;300.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;color&amp;nbsp;by&amp;nbsp;transition.animateColor(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transitionSpec&amp;nbsp;=&amp;nbsp;{&amp;nbsp;tween(300)&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;BoxColor&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;BoxState.Collapsed&amp;nbsp;-&amp;gt;&amp;nbsp;MaterialTheme.colorScheme.primaryContainer
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BoxState.Expanded&amp;nbsp;-&amp;gt;&amp;nbsp;MaterialTheme.colorScheme.tertiaryContainer
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&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;transitionSpec&amp;nbsp;=&amp;nbsp;{&amp;nbsp;tween(300)&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;CornerRadius&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;BoxState.Collapsed&amp;nbsp;-&amp;gt;&amp;nbsp;50.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;BoxState.Expanded&amp;nbsp;-&amp;gt;&amp;nbsp;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;&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;.size(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;.background(color,&amp;nbsp;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;.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;currentState&amp;nbsp;=&amp;nbsp;when&amp;nbsp;(currentState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BoxState.Collapsed&amp;nbsp;-&amp;gt;&amp;nbsp;BoxState.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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BoxState.Expanded&amp;nbsp;-&amp;gt;&amp;nbsp;BoxState.Collapsed
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;六、Infinite Transition：持续循环动画&lt;/h2&gt;&lt;p&gt;加载指示器、脉冲效果、背景渐变等需要持续播放的动画，使用 &lt;code&gt;rememberInfiniteTransition&lt;/code&gt; 是最优雅的方案。&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;PulsingDot()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;infiniteTransition&amp;nbsp;=&amp;nbsp;rememberInfiniteTransition(label&amp;nbsp;=&amp;nbsp;&amp;quot;PulseTransition&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;scale&amp;nbsp;by&amp;nbsp;infiniteTransition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;initialValue&amp;nbsp;=&amp;nbsp;0.8f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;1.2f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;infiniteRepeatable(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animation&amp;nbsp;=&amp;nbsp;tween(800,&amp;nbsp;easing&amp;nbsp;=&amp;nbsp;FastOutSlowInEasing),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;repeatMode&amp;nbsp;=&amp;nbsp;RepeatMode.Reverse
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;PulseScale&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;val&amp;nbsp;alpha&amp;nbsp;by&amp;nbsp;infiniteTransition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;initialValue&amp;nbsp;=&amp;nbsp;0.4f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;1.0f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;infiniteRepeatable(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animation&amp;nbsp;=&amp;nbsp;tween(800,&amp;nbsp;easing&amp;nbsp;=&amp;nbsp;LinearEasing),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;repeatMode&amp;nbsp;=&amp;nbsp;RepeatMode.Reverse
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;PulseAlpha&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;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;.size(20.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;.scale(scale)
&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.background(MaterialTheme.colorScheme.primary,&amp;nbsp;CircleShape)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
}

//&amp;nbsp;Shimmer&amp;nbsp;骨架屏效果
@Composable
fun&amp;nbsp;ShimmerEffect(modifier:&amp;nbsp;Modifier&amp;nbsp;=&amp;nbsp;Modifier)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;infiniteTransition&amp;nbsp;=&amp;nbsp;rememberInfiniteTransition(label&amp;nbsp;=&amp;nbsp;&amp;quot;Shimmer&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;shimmerTranslate&amp;nbsp;by&amp;nbsp;infiniteTransition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;initialValue&amp;nbsp;=&amp;nbsp;0f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetValue&amp;nbsp;=&amp;nbsp;1000f,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animationSpec&amp;nbsp;=&amp;nbsp;infiniteRepeatable(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animation&amp;nbsp;=&amp;nbsp;tween(1200,&amp;nbsp;easing&amp;nbsp;=&amp;nbsp;LinearEasing),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;repeatMode&amp;nbsp;=&amp;nbsp;RepeatMode.Restart
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;ShimmerTranslate&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;val&amp;nbsp;shimmerBrush&amp;nbsp;=&amp;nbsp;Brush.linearGradient(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;colors&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;Color.LightGray.copy(alpha&amp;nbsp;=&amp;nbsp;0.6f),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Color.LightGray.copy(alpha&amp;nbsp;=&amp;nbsp;0.2f),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Color.LightGray.copy(alpha&amp;nbsp;=&amp;nbsp;0.6f)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;start&amp;nbsp;=&amp;nbsp;Offset(shimmerTranslate&amp;nbsp;-&amp;nbsp;300f,&amp;nbsp;0f),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&amp;nbsp;=&amp;nbsp;Offset(shimmerTranslate,&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;Box(modifier&amp;nbsp;=&amp;nbsp;modifier.background(shimmerBrush))
}&lt;/pre&gt;&lt;h2&gt;七、动画性能优化：避免重组陷阱&lt;/h2&gt;&lt;p&gt;动画性能问题往往源于不必要的重组（Recomposition）。以下是几个关键的优化策略：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用 derivedStateOf 减少重组：&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;错误：每次滚动都触发重组
@Composable
fun&amp;nbsp;HeaderWithAnimation(listState:&amp;nbsp;LazyListState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;showHeader&amp;nbsp;=&amp;nbsp;listState.firstVisibleItemIndex&amp;nbsp;&amp;gt;&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedVisibility(visible&amp;nbsp;=&amp;nbsp;showHeader)&amp;nbsp;{&amp;nbsp;Header()&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;正确：通过&amp;nbsp;derivedStateOf&amp;nbsp;控制重组粒度
@Composable
fun&amp;nbsp;HeaderWithAnimation(listState:&amp;nbsp;LazyListState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;showHeader&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnimatedVisibility(visible&amp;nbsp;=&amp;nbsp;showHeader)&amp;nbsp;{&amp;nbsp;Header()&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;使用 graphicsLayer 实现 GPU 加速：&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;✅&amp;nbsp;graphicsLayer&amp;nbsp;修改在&amp;nbsp;Drawing&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;alpha&amp;nbsp;=&amp;nbsp;animatedAlpha
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaleX&amp;nbsp;=&amp;nbsp;animatedScale
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaleY&amp;nbsp;=&amp;nbsp;animatedScale
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;translationY&amp;nbsp;=&amp;nbsp;animatedOffset
&amp;nbsp;&amp;nbsp;&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;code&gt;Modifier.graphicsLayer&lt;/code&gt; 替代直接修改 &lt;code&gt;alpha&lt;/code&gt;、&lt;code&gt;scale&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;将动画读取操作（如 &lt;code&gt;animatable.value&lt;/code&gt;）下移到 &lt;code&gt;graphicsLayer&lt;/code&gt; 或 &lt;code&gt;DrawModifier&lt;/code&gt; 的 lambda 中，避免触发父组件重组&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;Layout&lt;/code&gt; 阶段的 &lt;code&gt;Modifier.layout&lt;/code&gt; 处理位置动画，而非 &lt;code&gt;Modifier.offset&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对长列表中的动画元素，考虑使用 &lt;code&gt;key()&lt;/code&gt; 稳定重组标识&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;通过 Android Studio 的 Layout Inspector 和 Compose Animation Preview 分析动画性能&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;八、实战案例：打造流畅的底部导航栏动画&lt;/h2&gt;&lt;p&gt;综合运用上述技术，实现一个带有指示器滑动、图标缩放和标签淡入淡出效果的底部导航栏：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;AnimatedBottomNavigation(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items:&amp;nbsp;List,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;selectedIndex:&amp;nbsp;Int,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onItemSelected:&amp;nbsp;(Int)&amp;nbsp;-&amp;gt;&amp;nbsp;Unit
)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;indicatorOffset&amp;nbsp;=&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;Animatable(0f)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;itemWidth&amp;nbsp;=&amp;nbsp;remember&amp;nbsp;{&amp;nbsp;mutableStateOf(0f)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LaunchedEffect(selectedIndex,&amp;nbsp;itemWidth.value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;indicatorOffset.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;targetValue&amp;nbsp;=&amp;nbsp;selectedIndex&amp;nbsp;*&amp;nbsp;itemWidth.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;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;dampingRatio&amp;nbsp;=&amp;nbsp;Spring.DampingRatioNoBouncy,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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.StiffnessMedium
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&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;&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;&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;.width(itemWidth.value.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;.height(3.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;.offset(x&amp;nbsp;=&amp;nbsp;indicatorOffset.value.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;.background(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RoundedCornerShape(bottomStart&amp;nbsp;=&amp;nbsp;2.dp,&amp;nbsp;bottomEnd&amp;nbsp;=&amp;nbsp;2.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;.align(Alignment.TopStart)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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(modifier&amp;nbsp;=&amp;nbsp;Modifier.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;items.forEachIndexed&amp;nbsp;{&amp;nbsp;index,&amp;nbsp;item&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;isSelected&amp;nbsp;=&amp;nbsp;index&amp;nbsp;==&amp;nbsp;selectedIndex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;transition&amp;nbsp;=&amp;nbsp;updateTransition(isSelected,&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;NavItem$index&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;val&amp;nbsp;iconScale&amp;nbsp;by&amp;nbsp;transition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&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;IconScale&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;selected&amp;nbsp;-&amp;gt;&amp;nbsp;if&amp;nbsp;(selected)&amp;nbsp;1.1f&amp;nbsp;else&amp;nbsp;1.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;val&amp;nbsp;labelAlpha&amp;nbsp;by&amp;nbsp;transition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transitionSpec&amp;nbsp;=&amp;nbsp;{&amp;nbsp;tween(200)&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;LabelAlpha&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;selected&amp;nbsp;-&amp;gt;&amp;nbsp;if&amp;nbsp;(selected)&amp;nbsp;1f&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;&amp;nbsp;&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(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;.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;.onGloballyPositioned&amp;nbsp;{&amp;nbsp;itemWidth.value&amp;nbsp;=&amp;nbsp;it.size.width.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;.clickable&amp;nbsp;{&amp;nbsp;onItemSelected(index)&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;horizontalAlignment&amp;nbsp;=&amp;nbsp;Alignment.CenterHorizontally
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;imageVector&amp;nbsp;=&amp;nbsp;if&amp;nbsp;(isSelected)&amp;nbsp;item.selectedIcon&amp;nbsp;else&amp;nbsp;item.unselectedIcon,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;item.label,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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.scale(iconScale)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;item.label,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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.alpha(labelAlpha),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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.labelSmall
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&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;通过以上八个方面的深入学习，你应该已经掌握了 Jetpack Compose 动画系统的进阶用法。动画不仅仅是视觉效果，更是提升用户体验、传达应用状态的重要手段。建议在实际项目中从简单的 &lt;code&gt;AnimatedVisibility&lt;/code&gt; 开始，逐步引入更复杂的动画技术，始终以用户体验为导向，避免为动画而动画。&lt;/p&gt;</description><pubDate>Thu, 03 Sep 2026 08:04:51 +0800</pubDate></item><item><title>四大向量数据库深度对比：Faiss Milvus Qdrant Weaviate 选型实战</title><link>https://blog.resmic.cn/post/372.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260902080228178830734817501.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;为什么向量数据库在 AI 时代不可或缺&lt;/h2&gt;&lt;p&gt;随着大语言模型（LLM）和生成式 AI 的爆发，向量相似度搜索已成为 RAG（检索增强生成）、语义搜索、推荐系统的标配技术。传统关系型数据库在处理高维向量时力不从心，而专门为此设计的向量数据库则能在毫秒级别完成百亿级向量的近似最近邻（ANN）搜索。&lt;/p&gt;&lt;p&gt;2026 年，向量数据库赛道已高度成熟，主流选手包括：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faiss&lt;/strong&gt;：Meta 开源的纯 C++ 向量检索库，极致性能&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Milvus&lt;/strong&gt;：云原生分布式向量数据库，企业级首选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Qdrant&lt;/strong&gt;：Rust 编写的高性能向量引擎，资源占用极低&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Weaviate&lt;/strong&gt;：带 GraphQL 接口的知识图谱型向量数据库&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;本文将从架构、性能、运维三个维度进行深度对比，帮你做出正确选型。&lt;/p&gt;&lt;h2&gt;核心概念：向量索引算法全解&lt;/h2&gt;&lt;p&gt;在比较各产品之前，先理解底层算法差异，这是性能差距的根本原因。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;HNSW（Hierarchical Navigable Small World）&lt;/strong&gt;：目前精度与速度综合最优的 ANN 算法，构建多层跳表结构，查询时从顶层快速定位候选集，再逐层精化。Qdrant、Weaviate、Milvus 均以 HNSW 为默认索引。&lt;/p&gt;&lt;p&gt;HNSW 的关键参数包括 m（每个节点连接数，越大精度越高但内存更大）、ef_construction（构建时动态候选集大小）和 ef（查询时候选集大小，影响召回率）。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IVF（Inverted File Index）&lt;/strong&gt;：将向量空间划分为 nlist 个聚类，查询时只搜索最近的 nprobe 个聚类。Faiss 的经典索引，适合超大规模场景（数十亿向量）。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ScaNN 与 DiskANN&lt;/strong&gt;：Google 的 ScaNN 在精度/速度帕累托前沿表现突出；DiskANN 专为超出内存限制的场景设计，将图索引存于 SSD，适合数百亿级向量。&lt;/p&gt;&lt;h2&gt;四大主流方案深度剖析&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. Faiss —— 性能极限的代名词&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Faiss 本质上是一个向量检索库而非完整数据库，没有持久化、没有 HTTP API，适合嵌入到应用层或作为其他系统的底层引擎。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;优势：单机 GPU 场景 QPS 可达百万级，CUDA 加速支持完善&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;劣势：无分布式能力，需要自研工程化层（HTTP API、持久化、监控）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;适用场景：图像/视频相似搜索引擎、超大规模批量检索&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;2. Milvus —— 企业级云原生首选&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Milvus 2.x 完全重写为微服务架构，支持 Kubernetes 部署，存算分离设计让其成为生产环境的主流选择。支持混合搜索（向量 + 标量过滤），是 RAG 场景的刚需。&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;劣势：部署复杂，依赖 etcd/MinIO/Pulsar，资源消耗较大&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;适用场景：大规模企业生产环境、需要高可用的 RAG 系统&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;3. Qdrant —— Rust 打造的性能黑马&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Qdrant 用 Rust 编写，内存安全、无 GC 停顿，在相同硬件下内存使用量通常比 Java/Go 系竞品低 30%-50%。独特的 Payload 索引让混合查询无需 post-filter 截断，召回精度显著优于竞品。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;优势：内存占用最低、部署简单（单二进制）、API 设计优雅&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;劣势：集群版在超大规模（10 亿+）性能略弱于 Milvus&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;适用场景：中小规模生产环境、边缘设备、快速上线的 AI 产品&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;4. Weaviate —— 知识图谱与向量的融合&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Weaviate 内置 GraphQL 接口和模块化 vectorizer（直接对接 OpenAI/Cohere API 自动生成 embedding），适合快速原型和知识图谱场景。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;优势：内置 vectorizer 省去 embedding 管道、支持对象关联查询&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;劣势：内存消耗最大，性能在四者中较低&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;适用场景：快速 POC、知识图谱应用、多模态搜索&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;性能基准测试：真实数据说话&lt;/h2&gt;&lt;p&gt;测试环境：AWS r6i.2xlarge（8 vCPU, 64GB RAM），数据集：100 万条 1536 维向量（OpenAI text-embedding-3-small），召回率目标 Recall@10 = 95%。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faiss（IVF+HNSW，GPU）&lt;/strong&gt;：QPS 280,000 / P99 延迟 0.8ms / 内存 12GB&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Qdrant（HNSW）&lt;/strong&gt;：QPS 18,500 / P99 延迟 3.2ms / 内存 9.8GB&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Milvus（HNSW）&lt;/strong&gt;：QPS 14,200 / P99 延迟 5.1ms / 内存 14.3GB&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Weaviate（HNSW）&lt;/strong&gt;：QPS 9,800 / P99 延迟 8.7ms / 内存 18.6GB&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;关键结论：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;纯性能追求 → Faiss + GPU（但需自研工程层）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;资源受限（如边缘设备、小团队）→ Qdrant（内存最省，运维最简）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;企业大规模生产 → Milvus（分布式、多租户、完善监控）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;快速原型 / 知识图谱 → Weaviate（内置 vectorizer 省去 embedding 管道）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;RAG 场景最佳实践&lt;/h2&gt;&lt;p&gt;构建生产级 RAG 系统时，向量库只是其中一环，完整架构还需要考虑以下几点：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;文档预处理&lt;/strong&gt;：使用递归文本分割器将文档切分为 512 token 的块，重叠 64 token，保证语义连贯性。分隔符优先级建议为：段落 &amp;gt; 换行 &amp;gt; 句号 &amp;gt; 其他。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Embedding 选型&lt;/strong&gt;：OpenAI text-embedding-3-small 在性价比上目前最优（1536 维，成本低于 ada-002 但效果更好）。本地部署可选 BGE-M3 或 E5-mistral-7b。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;检索增强策略&lt;/strong&gt;：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;混合检索：向量搜索 + BM25 关键词搜索加权融合（RRF 算法），召回率提升 15-20%&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;MMR（Maximum Marginal Relevance）：减少结果中的重复内容，提升信息密度&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;HyDE（Hypothetical Document Embedding）：先用 LLM 生成假设答案，再用其向量检索&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;生产优化&lt;/strong&gt;：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;Embedding 缓存：用 Redis 缓存高频查询的向量，节省 API 费用 60%+&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;分片策略：按时间或业务线分 Collection，避免单集合过大导致内存压力&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;量化压缩：使用 int8 量化可将内存降低 75%，精度损失小于 2%&lt;/p&gt;&lt;/li&gt;&lt;/ul&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;数据量小于 100 万，团队规模小 → &lt;strong&gt;Qdrant（单机模式）&lt;/strong&gt;，30 分钟上线&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;数据量 100 万到 1 亿，需要分布式 → &lt;strong&gt;Milvus&lt;/strong&gt;，稳定可靠&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;数据量超过 10 亿，且有 GPU 预算 → &lt;strong&gt;Faiss + 自研工程层&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;需要快速 POC，且希望内置 embedding → &lt;strong&gt;Weaviate&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;已有 PostgreSQL 基础设施 → 考虑 &lt;strong&gt;pgvector&lt;/strong&gt;（简单场景的最小成本方案）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;向量数据库的选型没有银弹，关键是匹配自身的数据规模、团队能力和预算约束。建议先用 Qdrant 快速验证业务价值，规模增长后再迁移到 Milvus 或 Faiss 方案。各大向量数据库都提供了完善的 Python SDK，集成成本很低，不妨先跑一个 Hello World 再做决策。&lt;/p&gt;</description><pubDate>Wed, 02 Sep 2026 08:09:04 +0800</pubDate></item><item><title>Jetpack Compose 动画实战：打造流畅自然的 Android UI 交互体验</title><link>https://blog.resmic.cn/post/371.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/09/20260901080422178822106246906.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;为什么选择 Compose 动画？&lt;/h2&gt;&lt;p&gt;在 Android 传统 View 体系中，实现复杂动画往往需要编写大量样板代码：ObjectAnimator、ValueAnimator、AnimatorSet 相互嵌套，维护成本极高。Jetpack Compose 的动画系统以声明式语法重新定义了这一体验——状态变化即触发动画，代码量减少 60% 以上，同时性能更优。&lt;/p&gt;&lt;p&gt;Compose 动画与 UI 状态深度绑定，每当状态发生变化，框架会自动计算插值并重新组合（recompose），无需手动管理动画生命周期。这种设计不仅降低了心智负担，还天然避免了传统动画中常见的内存泄漏问题。&lt;/p&gt;&lt;h2&gt;基础动画 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;animateFloatAsState&lt;/strong&gt;：用于平滑过渡单个 Float 值，适合透明度、缩放等场景&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;animateDpAsState&lt;/strong&gt;：用于尺寸、间距等 Dp 值的动画过渡&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;animateColorAsState&lt;/strong&gt;：颜色渐变动画，常用于主题切换、状态反馈&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;animateContentSize&lt;/strong&gt;：Modifier 扩展，自动对组件尺寸变化添加动画&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;AnimatedButton()&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;val&amp;nbsp;scale&amp;nbsp;by&amp;nbsp;animateFloatAsState(
&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;1.2f&amp;nbsp;else&amp;nbsp;1.0f,
&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;buttonScale&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Button(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onClick&amp;nbsp;=&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;modifier&amp;nbsp;=&amp;nbsp;Modifier.graphicsLayer(scaleX&amp;nbsp;=&amp;nbsp;scale,&amp;nbsp;scaleY&amp;nbsp;=&amp;nbsp;scale)
&amp;nbsp;&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(if&amp;nbsp;(expanded)&amp;nbsp;&amp;quot;收起&amp;quot;&amp;nbsp;else&amp;nbsp;&amp;quot;展开&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;AnimatedVisibility 控制显隐动画&lt;/h2&gt;&lt;p&gt;AnimatedVisibility 是 Compose 中控制组件显示/隐藏最优雅的方式，内置多种进入/退出动画效果，支持自由组合：&lt;/p&gt;&lt;pre&gt;@Composable
fun&amp;nbsp;NotificationBanner(show:&amp;nbsp;Boolean,&amp;nbsp;message:&amp;nbsp;String)&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;visible&amp;nbsp;=&amp;nbsp;show,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enter&amp;nbsp;=&amp;nbsp;slideInVertically(initialOffsetY&amp;nbsp;=&amp;nbsp;{&amp;nbsp;-it&amp;nbsp;})&amp;nbsp;+&amp;nbsp;fadeIn(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit&amp;nbsp;=&amp;nbsp;slideOutVertically(targetOffsetY&amp;nbsp;=&amp;nbsp;{&amp;nbsp;-it&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;Surface(
&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.fillMaxWidth().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;color&amp;nbsp;=&amp;nbsp;MaterialTheme.colorScheme.primaryContainer,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shape&amp;nbsp;=&amp;nbsp;RoundedCornerShape(12.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;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;text&amp;nbsp;=&amp;nbsp;message,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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(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;&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;}
}&lt;/pre&gt;&lt;p&gt;常用 EnterTransition 包括：fadeIn、slideInHorizontally、slideInVertically、expandIn、scaleIn；对应的 ExitTransition 则以 Out 结尾。多个效果通过 &lt;code&gt;+&lt;/code&gt; 运算符组合，执行时并行播放。&lt;/p&gt;&lt;h2&gt;Transition API 实现多属性联动动画&lt;/h2&gt;&lt;p&gt;当需要多个属性同步变化时，使用 updateTransition 可以将它们统一管理，确保动画保持同步：&lt;/p&gt;&lt;pre&gt;enum&amp;nbsp;class&amp;nbsp;CardState&amp;nbsp;{&amp;nbsp;Collapsed,&amp;nbsp;Expanded&amp;nbsp;}

@Composable
fun&amp;nbsp;AnimatedCard(cardState:&amp;nbsp;CardState)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;transition&amp;nbsp;=&amp;nbsp;updateTransition(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;targetState&amp;nbsp;=&amp;nbsp;cardState,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label&amp;nbsp;=&amp;nbsp;&amp;quot;cardTransition&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;cardHeight&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;tween(durationMillis&amp;nbsp;=&amp;nbsp;300)&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;cardHeight&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;if&amp;nbsp;(state&amp;nbsp;==&amp;nbsp;CardState.Expanded)&amp;nbsp;200.dp&amp;nbsp;else&amp;nbsp;80.dp
&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;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;cornerRadius&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;if&amp;nbsp;(state&amp;nbsp;==&amp;nbsp;CardState.Expanded)&amp;nbsp;16.dp&amp;nbsp;else&amp;nbsp;8.dp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;alpha&amp;nbsp;by&amp;nbsp;transition.animateFloat(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transitionSpec&amp;nbsp;=&amp;nbsp;{&amp;nbsp;tween(200)&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;contentAlpha&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;if&amp;nbsp;(state&amp;nbsp;==&amp;nbsp;CardState.Expanded)&amp;nbsp;1f&amp;nbsp;else&amp;nbsp;0f
&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;.height(cardHeight),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shape&amp;nbsp;=&amp;nbsp;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;&amp;nbsp;Box(modifier&amp;nbsp;=&amp;nbsp;Modifier.alpha(alpha))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;展开后的详细内容
&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;Compose 动画虽然简洁，但使用不当也会带来性能问题。以下几点是实际项目中常遇到的优化点：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;使用 graphicsLayer 而非直接修改布局属性&lt;/strong&gt;：graphicsLayer 的 scaleX/scaleY/alpha/translationX/Y 等属性变化不会触发 recompose，直接在 RenderThread 执行，性能最佳&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;避免在动画中执行昂贵计算&lt;/strong&gt;：animationSpec 的 lambda 在每帧都会被调用，应保持轻量；复杂计算移到 LaunchedEffect 中预处理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;为 animateXxxAsState 指定 label&lt;/strong&gt;：从 Compose 1.3 开始，label 参数有助于 Layout Inspector 的动画调试追踪&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;InfiniteTransition 注意取消&lt;/strong&gt;：使用 rememberInfiniteTransition 创建的无限动画会随组件离开组合树自动停止，无需手动取消&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;✅&amp;nbsp;推荐：使用&amp;nbsp;graphicsLayer，不触发&amp;nbsp;recompose
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;translationX&amp;nbsp;=&amp;nbsp;offsetX.value
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alpha&amp;nbsp;=&amp;nbsp;alphaValue.value
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
)

//&amp;nbsp;⚠️&amp;nbsp;避免：直接修改&amp;nbsp;offset/padding&amp;nbsp;会触发&amp;nbsp;recompose
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;.offset(x&amp;nbsp;=&amp;nbsp;offsetX.value)&amp;nbsp;&amp;nbsp;//&amp;nbsp;触发布局重测
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.padding(alphaValue.value.dp)&amp;nbsp;&amp;nbsp;//&amp;nbsp;触发布局重测
)&lt;/pre&gt;&lt;p&gt;通过合理使用 Compose 动画系统，可以在不牺牲性能的前提下，为用户提供流畅自然的交互体验。建议在开发过程中配合 Android Studio 的 Animation Preview 功能实时预览效果，大幅提升开发效率。&lt;/p&gt;</description><pubDate>Tue, 01 Sep 2026 08:04:50 +0800</pubDate></item><item><title>vLLM vs TensorRT-LLM：大模型推理加速框架实战对比</title><link>https://blog.resmic.cn/post/370.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260830080546178804834694863.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;为什么推理加速如此关键？&lt;/h2&gt;&lt;p&gt;随着 GPT-4、Llama 3、Qwen2.5 等大语言模型的广泛落地，推理成本已成为制约商业化的最大障碍之一。一张 A100 GPU 的月租约 2000 美元，而一个 QPS 较高的推理服务往往需要数十张卡——如果不做加速优化，成本将直接劝退大多数业务团队。&lt;/p&gt;&lt;p&gt;本文聚焦两大主流开源推理框架：&lt;strong&gt;vLLM&lt;/strong&gt; 和 &lt;strong&gt;TensorRT-LLM&lt;/strong&gt;，从原理到实战全面对比，帮助工程师做出合理的技术选型。&lt;/p&gt;&lt;h2&gt;vLLM：PagedAttention 的革命&lt;/h2&gt;&lt;p&gt;vLLM 由 UC Berkeley 团队开发，核心创新是 &lt;strong&gt;PagedAttention&lt;/strong&gt; 技术——将 KV Cache 的内存管理类比操作系统的虚拟内存分页，彻底解决了传统推理框架中 KV Cache 碎片化导致的内存浪费问题。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;连续批处理（Continuous Batching）&lt;/strong&gt;：不再等待一个 batch 全部完成再开始下一个，而是动态插入新请求，GPU 利用率大幅提升&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;PagedAttention&lt;/strong&gt;：KV Cache 以固定大小的 Page（默认 16 tokens）为单位分配，内存利用率提升至 95% 以上&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;前缀缓存（Prefix Caching）&lt;/strong&gt;：对相同前缀的请求复用 KV Cache，适合 System Prompt 固定的场景&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;投机解码（Speculative Decoding）&lt;/strong&gt;：用小模型预测 token，大模型批量验证，可降低 30-50% 延迟&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;快速启动 vLLM 服务：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;安装&amp;nbsp;vLLM（推荐&amp;nbsp;CUDA&amp;nbsp;12.1&amp;nbsp;+&amp;nbsp;Python&amp;nbsp;3.10）
pip&amp;nbsp;install&amp;nbsp;vllm

#&amp;nbsp;启动&amp;nbsp;OpenAI&amp;nbsp;兼容接口
python&amp;nbsp;-m&amp;nbsp;vllm.entrypoints.openai.api_server&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--model&amp;nbsp;Qwen/Qwen2.5-7B-Instruct&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--dtype&amp;nbsp;bfloat16&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--max-model-len&amp;nbsp;8192&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--gpu-memory-utilization&amp;nbsp;0.90&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--enable-prefix-caching&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--port&amp;nbsp;8000&lt;/pre&gt;&lt;h2&gt;TensorRT-LLM：NVIDIA 的极致优化&lt;/h2&gt;&lt;p&gt;TensorRT-LLM 是 NVIDIA 官方推出的推理加速库，基于 TensorRT 深度优化，能够针对特定 GPU 型号（如 H100、A100）生成最优计算图。其性能天花板通常高于 vLLM，但部署复杂度也更高。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;In-flight Batching&lt;/strong&gt;：类似 vLLM 的连续批处理，NVIDIA 的官方实现&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;量化支持&lt;/strong&gt;：原生支持 INT8、FP8、AWQ、GPTQ 等多种量化方案&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;自定义 CUDA Kernel&lt;/strong&gt;：针对 FlashAttention、RoPE、LayerNorm 等操作深度优化&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;多 GPU 并行&lt;/strong&gt;：张量并行（TP）和流水线并行（PP）开箱即用&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;#&amp;nbsp;构建&amp;nbsp;TensorRT-LLM&amp;nbsp;引擎（以&amp;nbsp;Llama-3-8B&amp;nbsp;为例）
git&amp;nbsp;clone&amp;nbsp;https://github.com/NVIDIA/TensorRT-LLM
cd&amp;nbsp;TensorRT-LLM

#&amp;nbsp;转换权重
python&amp;nbsp;examples/llama/convert_checkpoint.py&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--model_dir&amp;nbsp;/models/Llama-3-8B&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--output_dir&amp;nbsp;/tmp/trt_ckpt&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--dtype&amp;nbsp;float16

#&amp;nbsp;编译引擎（A100&amp;nbsp;80G，TP=1）
trtllm-build&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--checkpoint_dir&amp;nbsp;/tmp/trt_ckpt&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--output_dir&amp;nbsp;/tmp/trt_engine&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--max_batch_size&amp;nbsp;32&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--max_input_len&amp;nbsp;2048&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--max_output_len&amp;nbsp;1024&amp;nbsp;\
&amp;nbsp;&amp;nbsp;--gemm_plugin&amp;nbsp;float16&lt;/pre&gt;&lt;h2&gt;性能实测对比&lt;/h2&gt;&lt;p&gt;以下数据基于 &lt;strong&gt;单张 A100 80G&lt;/strong&gt;，模型为 Qwen2.5-7B-Instruct，输入 512 tokens，输出 256 tokens，并发 32：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;vLLM（默认配置）&lt;/strong&gt;：吞吐量约 1800 tokens/s，P99 延迟 ~1.2s&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;vLLM（开启前缀缓存 + FP8）&lt;/strong&gt;：吞吐量约 2400 tokens/s，P99 延迟 ~0.9s&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;TensorRT-LLM（FP16）&lt;/strong&gt;：吞吐量约 3100 tokens/s，P99 延迟 ~0.7s&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;TensorRT-LLM（INT8 量化）&lt;/strong&gt;：吞吐量约 4200 tokens/s，P99 延迟 ~0.5s，精度损失 &amp;lt;1%&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;总体而言，TensorRT-LLM 的峰值性能领先约 30-70%，但代价是显著更高的部署运维成本。&lt;/p&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;快速验证 / PoC 阶段&lt;/strong&gt;：首选 vLLM，5 分钟起服务，API 兼容 OpenAI，生态成熟&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;高并发在线推理（QPS &amp;gt; 100）&lt;/strong&gt;：TensorRT-LLM + Triton Inference Server，追求极限吞吐&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;多模型混合部署&lt;/strong&gt;：vLLM 支持动态加载，更灵活&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;边缘/云端混合&lt;/strong&gt;：考虑 llama.cpp 或 MLC-LLM，CPU 推理也能跑&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;无论选择哪个框架，以下通用优化都值得实施：&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;量化压缩（以&amp;nbsp;AWQ&amp;nbsp;4bit&amp;nbsp;为例，可节省约&amp;nbsp;60%&amp;nbsp;显存）
pip&amp;nbsp;install&amp;nbsp;autoawq
python&amp;nbsp;-c&amp;nbsp;&amp;quot;
from&amp;nbsp;awq&amp;nbsp;import&amp;nbsp;AutoAWQForCausalLM
from&amp;nbsp;transformers&amp;nbsp;import&amp;nbsp;AutoTokenizer

model&amp;nbsp;=&amp;nbsp;AutoAWQForCausalLM.from_pretrained(&amp;#39;Qwen/Qwen2.5-7B-Instruct&amp;#39;)
tokenizer&amp;nbsp;=&amp;nbsp;AutoTokenizer.from_pretrained(&amp;#39;Qwen/Qwen2.5-7B-Instruct&amp;#39;)
quant_config&amp;nbsp;=&amp;nbsp;{&amp;#39;zero_point&amp;#39;:&amp;nbsp;True,&amp;nbsp;&amp;#39;q_group_size&amp;#39;:&amp;nbsp;128,&amp;nbsp;&amp;#39;w_bit&amp;#39;:&amp;nbsp;4,&amp;nbsp;&amp;#39;version&amp;#39;:&amp;nbsp;&amp;#39;GEMM&amp;#39;}
model.quantize(tokenizer,&amp;nbsp;quant_config=quant_config)
model.save_quantized(&amp;#39;./qwen2.5-7b-awq&amp;#39;)
&amp;quot;&lt;/pre&gt;&lt;p&gt;最终建议：&lt;strong&gt;从 vLLM 起步，在性能瓶颈出现后再迁移至 TensorRT-LLM&lt;/strong&gt;。这条路线在工程上最为稳健，避免过早优化带来的维护负担。&lt;/p&gt;</description><pubDate>Mon, 31 Aug 2026 08:02:54 +0800</pubDate></item><item><title>PHP 8.3 新特性实战：类常量类型化与性能提升全面解析</title><link>https://blog.resmic.cn/post/369.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260830080546178804834694863.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;PHP 8.3 简介：2023 年最重要的版本升级&lt;/h2&gt;
&lt;p&gt;PHP 8.3 于 2023 年 11 月正式发布，是 PHP 8.x 系列的又一重要里程碑。相比 8.2，这个版本在类型系统、只读特性、标准库函数以及性能方面都做了有针对性的改进。如果你的项目还在使用 PHP 8.1 或更早版本，升级到 8.3 将带来可观的性能收益和更现代的编程体验。&lt;/p&gt;
&lt;p&gt;本文将聚焦几个最具实用价值的新特性，带你快速了解这次升级的亮点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;类常量类型化（Typed Class Constants）&lt;/li&gt;
  &lt;li&gt;只读属性的克隆增强&lt;/li&gt;
  &lt;li&gt;新函数 json_validate() 简化 JSON 校验&lt;/li&gt;
  &lt;li&gt;随机数 API 持续完善&lt;/li&gt;
  &lt;li&gt;性能与 JIT 进一步优化&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;一、类常量类型化：更严格的接口契约&lt;/h2&gt;
&lt;p&gt;PHP 8.3 引入了类型化类常量，允许开发者为接口和类的常量声明具体类型，如 int、string、float、bool 等。这个改进解决了长期以来子类可以随意覆盖父类常量类型导致的运行时错误问题。&lt;/p&gt;
&lt;p&gt;有了类型化类常量，编写公共库和框架时可以通过编译时检查确保常量类型的一致性，大幅减少因类型不匹配引发的难以排查的 bug。对于维护大型 PHP 项目的团队来说，这是一个实实在在的工程质量提升。&lt;/p&gt;
&lt;p&gt;支持的类型包括所有标量类型（int、float、string、bool）以及 array、object、null、iterable 等复合类型，与属性类型声明保持一致。&lt;/p&gt;

&lt;h2&gt;二、只读属性增强：克隆时可修改只读字段&lt;/h2&gt;
&lt;p&gt;PHP 8.1 引入了只读属性（readonly），但随之带来了一个实践难题：无法克隆一个对象并同时修改其只读属性，这让「Wither 模式」（创建修改过的副本而不改变原始对象）变得异常困难。&lt;/p&gt;
&lt;p&gt;PHP 8.3 解决了这个问题：在 clone 的过程中，可以对只读属性进行重新赋值。这让基于不可变值对象（Value Object）的 DDD 领域驱动设计更加自然流畅，同时保持了只读属性在正常使用中的安全性。&lt;/p&gt;
&lt;p&gt;这一改进在使用 Laravel、Symfony 等现代框架构建数据传输对象（DTO）时尤为便利，彻底解决了之前必须用构造函数全量重建对象的繁琐做法。&lt;/p&gt;

&lt;h2&gt;三、json_validate()：轻量 JSON 格式校验&lt;/h2&gt;
&lt;p&gt;在 PHP 8.3 之前，要验证一个字符串是否是合法 JSON，只能使用 json_decode() 解析后检查错误码。这种做法的缺点是需要完整解析整个 JSON 结构并在内存中构建 PHP 数据对象，即使你只需要确认格式是否正确。&lt;/p&gt;
&lt;p&gt;PHP 8.3 新增的 json_validate() 函数只做语法验证，不进行实际解析，因此内存占用极低。在高并发的消息队列消费场景、API 网关请求校验等场景下，使用 json_validate() 比 json_decode() 的内存开销可减少 30%~50%。&lt;/p&gt;
&lt;p&gt;推荐在实际开发中将其作为 API 入口的第一道校验关卡：先用 json_validate() 快速判断格式合法性，通过后再用 json_decode() 解析数据，这样既高效又清晰。&lt;/p&gt;

&lt;h2&gt;四、随机数 API 持续完善&lt;/h2&gt;
&lt;p&gt;PHP 8.2 引入了全新的面向对象随机数 API（Random\Randomizer），PHP 8.3 在此基础上新增了两个实用方法：getBytesFromString() 和 getFloat()。&lt;/p&gt;
&lt;p&gt;getBytesFromString() 允许从指定字符集中随机取出若干字符，非常适合生成验证码、邀请码、订单号等业务场景，并且通过排除易混淆字符（如 0 和 O、1 和 l）可以直接生成用户友好的随机码。&lt;/p&gt;
&lt;p&gt;getFloat() 则支持在指定浮点数范围内生成安全随机浮点数，对于需要精确控制随机范围的科学计算或游戏应用场景非常有用。配合不同的随机引擎（Secure、Mt19937、Xoshiro256StarStar），可以根据安全性需求灵活选择。&lt;/p&gt;

&lt;h2&gt;五、升级建议与兼容性说明&lt;/h2&gt;
&lt;p&gt;PHP 8.3 的向下兼容性相当好，大多数 PHP 8.x 项目可以平滑升级。需要注意的几个变化点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;类常量类型检查更严格&lt;/strong&gt;：若有子类覆盖父类常量且类型不匹配，升级后会抛出 Fatal Error，建议提前用 PHPStan 进行静态分析扫描。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;动态访问静态属性弃用&lt;/strong&gt;：某些动态形式的静态属性访问在 8.3 会触发弃用警告，建议替换为明确写法。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;随机数函数迁移建议&lt;/strong&gt;：逐步将 mt_rand()、rand() 替换为新的 Random\Randomizer，以获得更好的安全性和可测试性。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;性能收益&lt;/strong&gt;：升级后整体基准性能较 8.2 提升约 5%~8%，CPU 密集型任务（如复杂计算、大量数组操作）提升更为明显。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;升级前推荐先在 CI 环境用 PHPStan（level 8 以上）和 Rector（dry-run 模式）全面扫描代码库，确保没有类型不兼容问题。结合 Laravel 11 或 Symfony 7，PHP 8.3 能为企业级应用带来更健壮的类型安全和更优异的运行性能。立即行动，把你的项目升级到 PHP 8.3 吧！&lt;/p&gt;
</description><pubDate>Sun, 30 Aug 2026 08:11:52 +0800</pubDate></item><item><title>深入解析 PHP 8.4 全新特性：属性钩子、不对称可见性与实战升级指南</title><link>https://blog.resmic.cn/post/368.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/08/20260829080244178796176442988.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 已正式发布，作为 PHP 语言史上最重要的版本之一，带来了一系列令开发者振奋的核心改进。本文将系统梳理这些新特性，帮助你快速掌握并在项目中实践应用。&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;不对称可见性（Asymmetric Visibility）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增 array_find / array_any / array_all 等数组函数&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;/ul&gt;&lt;h2&gt;属性钩子：告别冗余的 getter/setter&lt;/h2&gt;&lt;p&gt;属性钩子（Property Hooks）是 PHP 8.4 中最受期待的特性。过去，为了给属性添加验证逻辑，我们不得不编写大量样板式的 getter/setter 方法。现在，PHP 允许直接在属性声明时内联钩子逻辑，让代码更简洁、更直观。&lt;/p&gt;&lt;p&gt;以用户类为例：可以为 name 属性定义 set 钩子，确保名称长度不小于2；为 email 属性同时定义 get 和 set 钩子，读取时自动转小写，写入时验证邮箱格式。这种写法极大提升了代码可读性，并将验证逻辑集中在属性声明处，减少了散落各处的样板代码。&lt;/p&gt;&lt;h2&gt;不对称可见性：灵活控制读写权限&lt;/h2&gt;&lt;p&gt;PHP 8.4 引入了不对称可见性（Asymmetric Visibility），允许开发者为属性的读操作和写操作设置不同的访问级别。通过 &lt;code&gt;public private(set)&lt;/code&gt; 这样的语法，可以轻松实现&amp;quot;外部只读、内部可写&amp;quot;的封装效果，无需编写额外的 getter 方法。&lt;/p&gt;&lt;p&gt;这一特性在构建只读 DTO（数据传输对象）或领域模型时尤为有用。例如，订单的总金额可以由内部方法累加，但外部代码不能直接修改，完美契合了领域驱动设计的封装原则。&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;code&gt;array_find()&lt;/code&gt; —— 返回满足条件的第一个元素值&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;array_find_key()&lt;/code&gt; —— 返回满足条件的第一个元素键名&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;array_any()&lt;/code&gt; —— 判断是否有元素满足条件&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;array_all()&lt;/code&gt; —— 判断是否所有元素都满足条件&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;这些函数与箭头函数（fn）配合使用时极为简洁，可以用一行表达过去需要多行 foreach 才能实现的查找、过滤逻辑，让代码更加语义化。&lt;/p&gt;&lt;h2&gt;JIT 改进与性能提升&lt;/h2&gt;&lt;p&gt;PHP 8.4 对 JIT（Just-In-Time）编译器进行了深度优化，引入了新的 IR（中间表示）框架，在 CPU 密集型任务上性能提升显著。根据官方基准测试，部分场景下执行速度提升可达 10%~20%。&lt;/p&gt;&lt;p&gt;开启方式：在 php.ini 中设置 &lt;code&gt;opcache.enable=1&lt;/code&gt;、&lt;code&gt;opcache.jit_buffer_size=128M&lt;/code&gt;、&lt;code&gt;opcache.jit=tracing&lt;/code&gt; 即可。对于 CPU 密集型业务（如批量数据计算、图像处理），建议在测试环境充分压测后再推广到生产。&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;隐式可空类型弃用&lt;/strong&gt;：函数参数默认值为 null 时需显式加 ? 前缀&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GD 扩展变更&lt;/strong&gt;：部分图像函数的质量参数行为有所调整&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;mbstring 别名移除&lt;/strong&gt;：部分 mb_* 函数的旧别名被清理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;SOAP 扩展变更&lt;/strong&gt;：类型映射行为有所调整&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;建议升级前使用 Rector（&lt;a href=&quot;https://github.com/rectorphp/rector&quot; target=&quot;_blank&quot;&gt;github.com/rectorphp/rector&lt;/a&gt;）工具自动检测和修复代码中的弃用用法：运行 &lt;code&gt;composer require rector/rector --dev&lt;/code&gt;，再执行 &lt;code&gt;vendor/bin/rector process src --dry-run&lt;/code&gt; 即可预览所有需要修改的位置。&lt;/p&gt;&lt;h2&gt;升级指南：从 PHP 8.3 平滑迁移&lt;/h2&gt;&lt;p&gt;PHP 8.4 与 PHP 8.3 高度兼容，对于大多数项目来说，升级过程相对平顺。推荐步骤如下：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;第一步&lt;/strong&gt;：在本地或测试环境安装 PHP 8.4，运行完整测试套件&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;第二步&lt;/strong&gt;：使用 php -l 检查语法错误，关注弃用警告&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;第三步&lt;/strong&gt;：更新 Composer 依赖，确保所有包支持 PHP 8.4（设置 require php: ^8.4）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;第四步&lt;/strong&gt;：用 Rector 自动修复弃用用法&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;PHP 8.4 是现代 PHP 发展历程中的重要里程碑。无论是属性钩子带来的优雅封装，还是新增数组函数的便利，都值得每一位 PHP 开发者尽早体验。现在就开始升级吧！&lt;/p&gt;</description><pubDate>Sat, 29 Aug 2026 08:06:43 +0800</pubDate></item></channel></rss>