ITPub博客

首页 > 移动开发 > ANDROID > Flutter 拖动会比原生更省资源?分析 GPU呈现模式条形图 不动的秘密

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

原创 ANDROID 作者:山有木xi 时间:2025-06-17 22:00:08 0 删除 编辑

前言:

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

一、 故事的开始

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

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

 

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

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

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

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

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 通常使用如下方式:

Transform.translate(
  offset: Offset(dx, dy),
  child: MyWidget(),
)


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

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

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

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(...)

示例:

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 坐标。

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


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69917874/viewspace-3088051/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle OCA(Java),IBM高级工程师认证,中国软件行业人才(高级c语言),高级Android工程师,对数据库并发与性能调优也有一定了解

注册时间:2019-04-25

  • 博文量
    147
  • 访问量
    390778