You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter中Text组件添加阴影导致raster thread占用过高、帧率骤降的问题求助

Flutter中Text组件添加阴影导致raster thread占用过高、帧率骤降的问题求助

兄弟我太懂你这种崩溃感了!之前做实时时钟类的项目时,也踩过Text阴影拖垮帧率的坑,来给你唠唠问题出在哪,还有几个亲测有效的解决办法:

首先得搞清楚为啥加了阴影帧率就崩了:Text的阴影是在**光栅化线程(raster thread)**里计算渲染的,这个线程本来就负责把Flutter的组件树转换成屏幕上的像素,算力很金贵。你这一口气放了20多个带阴影的Text,而且模糊半径(blurRadius)设到了10——高斯模糊本身就是计算量极大的操作,每个Text都要单独做一次模糊运算,再加上实时时钟每秒刷新一次,哪怕时钟本身没阴影,整个页面的绘制压力直接把光栅化线程跑满了,帧率自然就掉到姥姥家了。

接下来给你几个实操的解决思路,按改动从小到大排序:

  • 用RepaintBoundary缓存静态Text的绘制结果
    你页面里的text1到text20都是静态文本,完全没必要每次帧都重新计算它们的阴影。用RepaintBoundary把这些静态Text包起来,Flutter会把它们渲染成一个单独的缓存位图,只有第一次加载或者样式变化时才会计算阴影,之后就直接复用缓存的内容,能瞬间减轻光栅化线程的负担。代码改起来超简单:

    RepaintBoundary(
      child: Column(
        children: [
          Text("text1", style: style),
          Text("text2", style: style),
          // ... 剩下的静态Text都放这里面
        ],
      ),
    )
    
  • 优化阴影的参数
    你现在的blurRadius是10,这个值越大,模糊计算量就呈指数级增长。如果视觉效果允许,把它调到3-5之间,阴影的视觉差别不会太大,但计算量能砍一半以上。另外阴影的offset如果不需要那么大也可以调小,虽然影响没模糊半径大,但聊胜于无。

  • 用CustomPaint批量绘制带阴影的文本
    如果上面的方法还不够,就换个思路:把所有静态Text的阴影和文本一次性绘制在同一个画布上,避免多个Text组件的重复绘制开销。可以自定义一个Painter来干这个活:

    class ShadowTextPainter extends CustomPainter {
      final List<String> texts;
      final TextStyle style;
    
      ShadowTextPainter(this.texts, this.style);
    
      @override
      void paint(Canvas canvas, Size size) {
        // 分离文本样式和阴影,避免重复应用
        final textStyle = style.copyWith(shadows: null);
        final shadow = style.shadows?.first;
        final textPainter = TextPainter(textDirection: TextDirection.ltr);
        const lineHeight = 30.0; // 自己根据需求调整行高
    
        for (int i = 0; i < texts.length; i++) {
          final textSpan = TextSpan(text: texts[i], style: textStyle);
          textPainter.text = textSpan;
          textPainter.layout();
    
          // 先画阴影
          if (shadow != null) {
            canvas.save();
            canvas.translate(shadow.offset.dx, shadow.offset.dy);
            textPainter.paint(canvas, Offset(0, i * lineHeight));
            canvas.restore();
          }
          // 再画原文本
          textPainter.paint(canvas, Offset(0, i * lineHeight));
        }
      }
    
      @override
      bool shouldRepaint(covariant ShadowTextPainter oldDelegate) {
        return oldDelegate.texts != texts || oldDelegate.style != style;
      }
    }
    

    然后在页面里用CustomPaint调用这个Painter就行,这样所有静态文本的阴影只需要计算一次绘制一次,效率比多个Text组件高太多。

  • 确认DisplayTime的重建逻辑没问题
    虽然你给的代码里用了const DisplayTime(),这点很赞(const构造函数能避免不必要的重建),但还是要确认下DisplayTime内部有没有触发父组件的重建——比如有没有不小心调用了父组件的setState,或者用了会导致父组件重建的状态管理方式,这点也得排查下。

先从第一个方法试起,改动最小效果最明显,应该能解决大部分问题。如果还有帧率问题,再逐步尝试后面的方法。

内容来源于stack exchange

火山引擎 最新活动