Skip to content

Lab: Flutter asset 变体(1x 图在 3x 屏的放大发虚与变体匹配) ​

对应知识库文档:逻辑单位、资源倍率与图片解码:dp / dpi / scale 到内存(§底层机制 2 密度桶解码缩放 / §5 跨端对照 / §5.1 Flutter AssetImage 变体尺寸计算流程) 上级章节:屏幕适配:从清晰显示到动态窗口可用

这个 lab 验证什么 ​

在真实 Flutter 工程里验证文档讲的「按 devicePixelRatio 找 1.0x/2.0x/3.0x 变体、缺失时不额外解码重采样」:

  1. 内存不预放大解码:只有 1x 的图,不管设备 dpr 是 1.0 还是 4.0,解码像素恒为原像素(48×48)、key.scale 恒为 1.0——Flutter 不在内存里按 density 预重采样放大(对比 Android 低桶会被解码放大 ×9)。
  2. 逻辑尺寸与发虚(上屏) :自然尺寸渲染时固有逻辑尺寸 =48px/1.0=48dp,在 3x 屏上占据完整的 48dp 显示空间(绝对不缩小);但由于 48px 无法填满 3x 屏要求的 144px 物理点阵,48px 源被 GPU 放大拉满,肉眼可见偏软 / 模糊 / 锯齿。
  3. 变体选择规则:_chooseAsset 返回第一张 scale ≥ dpr 的变体,若一张都没有则回退最高档。滑块模拟 dpr 可实时观察:1.0→1x,1.5/2.0→2x,2.625/3.0→3x,4.0→回退 3x。

运行方式 ​

bash
cd labs/flutter/host
flutter pub get
flutter run          # 选一个模拟器/真机,进入首页后点「图片资源变体 Demo」

页面内容 ​

素材是程序生成的「网格 + 圆 + 角标」PNG(线宽随分辨率等比:1px@48 / 2px@96 / 3px@144),角标色 = 命中的变体(1x 蓝 / 2x 绿 / 3x 橙),肉眼即可分辨命中了哪一档:

素材像素说明
assets/asset_variant_demo/logo_1x_only.png48×48无任何变体,永远按 1.0x 解析 (scale=1.0)
assets/asset_variant_demo/logo.png48×481.0x(带 2.0x / 3.0x 变体)
assets/asset_variant_demo/2.0x/logo.png96×962.0x 变体
assets/asset_variant_demo/3.0x/logo.png144×1443.0x 变体

页面内:

  • 真实设备信息:真实 devicePixelRatio、素材规格、期望逻辑尺寸(120dp)。
  • 模拟 dpr 滑块(1.0~4.0):驱动下方「解码像素探针」,观察变体选择规则与解码像素。
  • 真机表现 A/B/C 三卡:
    • A · 只有 1x · 自然尺寸 → 渲染为 48dp 固有逻辑尺寸(无缩小),48px 点阵被 GPU 拉大发虚;
    • B · 只有 1x · 强制 120dp → 布局强制 120dp,48px 源被 GPU 放大至 360px(7.5×),严重马赛克 / 锯齿;
    • C · 带 1x/2x/3x · 自然尺寸 → 命中 3.0x(144px),144/3.0=48dp 固有尺寸,且 144px 点对点 1:1 绝对清晰。
  • 解码像素探针:同一模拟 dpr 下,对比「只有 1x」与「带变体」两份素材的解码结果。

预期现象 ​

  • 只有 1x 的素材:把滑块从 1.0 拖到 4.0,解码像素恒为 48×48、scale 恒为 1.0——「缺失不缩放」。
  • 带变体的素材:dpr=1.0 → 48×48(1.0x);dpr=2.0 → 96×96(2.0x);dpr=2.625 / 3.0 → 144×144(3.0x);dpr=4.0 → 仍 144×144(无 ≥4 的变体,回退最高档)。
  • 真机三卡:A 尺寸正常(48dp)但发虚偏软、B 糊、C 清晰;C 若也强制 120dp,同样会糊(变体只保证「设计逻辑尺寸」下的锐度,救不了超出设计尺寸的放大)。

代码入口 ​

  • asset_variant_demo_page.dart —— 演示页面(routeName = '/asset_variant_demo',_ImageInfoLine 用 AssetImage.resolve(ImageConfiguration(devicePixelRatio: dpr)) 实时打印解码结果)。
  • 路由注册:app_router.dart(import + route const + switch case + 首页列表项)。
  • 素材声明:pubspec.yaml 的 assets: 段(4 个文件,含 2.0x / 3.0x 变体目录)。
  • 素材生成脚本:generate_assets.py(纯 Python 手写 PNG,网格 + 圆 + 角标色;python3 generate_assets.py 可重新生成)。

站点构建时间:2026/8/24 23:43:17