Flutter 拖动会比原生更省资源?分析 GPU呈现模式条形图不动的秘密

前言:

Android拖拽view进行移动是一个很常见并且很"正常"的功能,在合理的逻辑中,可以实现并不复杂的运算,对于用户设备的性能消耗理论上也可以得到一个较好的支持。

一、故事的开始

最近我们有一个功能需要涉及到对view的变换和重新draw,在参考竞品的时候发现了一个神奇的现象,我们的应用在实际的操作中的性能已经算不错的了,但是竞品居然在拖动时一点"性能消耗"都没有。

在对比参考时,看了开发者模式中的gpu呈现条形图,如下:

发现竞品拖动一个 View 的同时,开发者选项中的 GPU 渲染条形图几乎不动!

对比自己项目中原生实现时 GPU/CPU 的剧烈波动,这让我陷入了思考:Flutter 是如何做到如此轻量拖动的?我们原生开发能否也做到?

二、 拖动为何会触发 GPU/CPU?

在原生 Android 中,当我们写出如下代码:

ini 复制代码
view.setOnTouchListener { v, event ->
    if (event.action == MotionEvent.ACTION_MOVE) {
        view.x = event.rawX
        view.y = event.rawY
    }
    true
}

简单的说,这背后会触发:

  • requestLayout()(视图重新布局)

  • invalidate()(视图重新绘制)

  • GPU 重排合成图层

三、Flutter 为何 GPU 条纹不动?

Flutter 的 Widget 是通过 Dart 层描述的 UI 元素,通过 Skia / Impeller 渲染引擎统一渲染为图形。

拖动时 Flutter 通常使用如下方式:

less 复制代码
Transform.translate(
  offset: Offset(dx, dy),
  child: MyWidget(),
)

Flutter 并没有修改 Widget 本身的位置,而是通过 GPU 层对渲染结果做了一个 transform 位移。

四、原生 Android 如何实现同样的效果?

可以用 translationX/Y 来避免重绘开销:

ini 复制代码
view.setOnTouchListener { v, event ->
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            offsetX = event.rawX - view.x
            offsetY = event.rawY - view.y
        }
        MotionEvent.ACTION_MOVE -> {
            view.translationX = event.rawX - offsetX
            view.translationY = event.rawY - offsetY
        }
    }
    true
}

这种方式不会改变布局位置,不触发布局,不触发重绘。

实测对比:GPU 条形图波动情况

操作方式 GPU 条波动 CPU 使用 动画流畅度
view.x/y 拖动 明显抖动 中到高 中等
translationX/Y 拖动 几乎无波动 极低 极流畅
Flutter Transform.translate 几乎无波动 极低 极流畅

五、为什么我没有使用 translationX/Y?

虽然 translationX/Y 性能很好,但在我的项目中,这种方式并不适合:

  • 我需要计算真实位置,用于碰撞检测或边界限制

  • 需要与缩放、旋转联动,不能坐标错乱

  • 拖动完成后需要保存精确坐标以便后续使用

而 translationX/Y 只是视觉效果,并不会改变 View 的实际 layout 坐标。

六、translationX/Y 本质解析:为什么只是视觉移动?

translationX 和 translationY 并不改变 View 的 layout 坐标,而是:

  • 在绘制前的最后一步,通过 GPU 对 canvas 添加一个偏移矩阵

  • 类似于 CSS 中的 transform: translate(...)

示例:

ini 复制代码
view.translationX = 100f
Log.d("Position", "x=${view.x}, left=${view.left}")

输出结果中 x 会变,但 left 不变,说明只是视觉上的平移。

七、何时使用 translationX/Y,何时使用真实位置?

场景 推荐方式 原因
简单拖动、平移展示 translationX/Y 性能好、无重绘
需要真实坐标计算 x/y 或 LayoutParams 必须与逻辑交互保持一致
拖动后参与动画 x/y 否则动画锚点偏移
与缩放/旋转/碰撞联动 x/y 否则坐标系统不统一
只看起来"动了" translationX/Y 无需修改真实位置

总结

Flutter 拖动时几乎不动 GPU,是因为它使用的是 GPU 层级的 transform 操作,而不是重新渲染视图。我们在原生开发中也完全可以做到这一点,只要你掌握了 translationX/Y 的使用方式。

但如果你需要更复杂的行为(如旋转、缩放、边界判断等),那就必须使用真实的 layout 坐标。

选择合适的方式,既要保证性能,也要兼顾功能需求。

公众号地址:mp.weixin.qq.com/s/nEJUiI-6H...

相关推荐
code bean1 小时前
【C#】 C#中 nameof 和 ToString () 的用法与区别详解
android·java·c#
佛系小嘟嘟2 小时前
Android Studio Jetpack Compose毛玻璃特效按钮
android·ide·android studio
马拉萨的春天3 小时前
flutter的widget的执行顺序,单个组建的执行顺序
flutter
怀君3 小时前
Flutter——数据库Drift开发详细教程(七)
数据库·flutter
月伤593 小时前
Flutter中将bytes转换成XFile对象上传
flutter
用户2018792831674 小时前
MagiskHidePropsConf 原理与实战故事
android
whysqwhw4 小时前
Egloo 项目结构分析
android
Wgllss5 小时前
大型异步下载器(二):基于kotlin+Compose+协程+Flow+Channel+ OKhttp 实现多文件异步同时分片断点续传下载
android·架构·android jetpack
yzpyzp5 小时前
KAPT 的版本如何升级,是跟随kotlin的版本吗
android·kotlin·gradle
泓博5 小时前
KMP(Kotlin Multiplatform)简单动画
android·开发语言·kotlin