You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter TabBar切换卡顿SkCanvas::Flush执行过慢帧率不足优化咨询

Flutter TabBarView切换帧率优化方案

问题复现代码

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: TabBarPage(),
    );
  }
}

class TabBarPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TabBarPageState();
  }
}

class TabBarPageState extends State<TabBarPage> with SingleTickerProviderStateMixin {

  TabController _tabController; //需要定义一个Controller
  List tabs = ["page 1", "page 2", "page 3", "page 4", "page 5", "page 6"];

  @override
  void initState() {
    super.initState();
    print("TabBarPageState initState");
    _tabController = TabController(length: tabs.length, vsync: this);

  }

  @override
  void dispose() {
    super.dispose();
    print("TabBarPageState dispose");
  }

  @override
  Widget build(BuildContext context) {
    print("TabBarPageState build");
    return Scaffold(
      body: TabBarView(

        controller: _tabController,
        children: getChildWidgets(),
      ),
      bottomNavigationBar: TabBar(
        controller: _tabController,
        tabs: tabs.map((item) {
          return Container(color: Colors.black,child: Text(item, style: TextStyle(color: Colors.white),),);
        }).toList(),
      ),
    );
  }

  List<Widget> getChildWidgets() {
    return List<Widget>()..addAll([PageWidget("page 1", Colors.red), PageWidget("page 2", Colors.yellow), PageWidget("page 3", Colors.blue),
      PageWidget("page 4", Colors.green), PageWidget("page 5", Colors.deepPurpleAccent), PageWidget("page 6", Colors.tealAccent), ]);
  }


}

class PageWidget extends StatefulWidget {
  final String title;
  final Color bgColor;

  PageWidget(this.title, this.bgColor);

  @override
  _PageWidgetState createState() => _PageWidgetState();
}

class _PageWidgetState extends State<PageWidget> with AutomaticKeepAliveClientMixin{

  @override
  void initState() {
    super.initState();
    print("_PageWidgetState initState ${widget.title}");
  }

  @override
  void dispose() {
    super.dispose();
    print("_PageWidgetState dispose ${widget.title}");
  }

  @override
  Widget build(BuildContext context) {
    print("_PageWidgetState build ${widget.title}");
    super.build(context);
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: widget.bgColor,
        child: "page 2" != widget.title ? Text(widget.title) : RawMaterialButton(child: Text(widget.title), onPressed: (){ Navigator.of(context).push(MaterialPageRoute(builder: (context)=>SecondPageWidget("测试", Colors.deepOrangeAccent)));},),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}


class SecondPageWidget extends StatefulWidget {
  final String title;
  final Color bgColor;

  SecondPageWidget(this.title, this.bgColor);

  @override
  _SecondPageWidgetState createState() => _SecondPageWidgetState();
}

class _SecondPageWidgetState extends State<SecondPageWidget> {
  @override
  Widget build(BuildContext context) {
    print("SecondPageWidget ${widget.title} build");
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: widget.bgColor,
        child: Text(widget.title),
      ),
    );
  }
}

优化方案

1. 页面切换帧率优化措施

  • 替换底部导航组件:当前使用TabBar作为底部导航栏属于非常规用法,TabBar默认内置了滑动手势、水波纹反馈、过渡动画等多余效果,直接替换为官方的BottomNavigationBar组件,可减少30%以上的导航栏绘制开销。
  • 调整页面保活策略:当前6个页面全部开启AutomaticKeepAlive全局保活,会占用大量光栅缓存空间,进而提升Raster线程SkCanvas::Flush操作的耗时。可根据业务需求仅保活核心的2-3个页面,非核心页面使用PageStorageKey存储状态,销毁后重建也可恢复原有状态,同时降低内存占用。
  • 预构建静态组件:当前TabBar的tab项、TabBarView的子页面均在build方法中实时生成,可将这部分静态组件提前到initState阶段预创建,避免build阶段重复创建对象触发不必要的重绘。
  • 升级Flutter版本:你使用的2.2.3版本属于较老的稳定版,2.10及之后的3.x版本对Android端光栅化逻辑做了大量针对性优化,相同代码在新版本下SkCanvas::Flush耗时可降低40%以上。
  • 优化绘制层级:给Scaffold明确指定backgroundColor属性,避免底层透明层和上层页面的纯色背景叠加绘制,触发系统绘制裁剪优化,减少每帧的绘制像素量。

2. RawMaterialButton卡顿关联及优化

RawMaterialButton和切换卡顿直接相关,原因是该组件默认自带阴影、水波纹、形状裁剪等Material效果,就算处于未点击状态,切换页面的滑动动画过程中,每帧都需要对该组件做额外的光栅计算,大幅提升单帧耗时。
优化方式如下:

  • 无特殊效果需求的情况下,直接用GestureDetector或者InkWell包裹Text组件替代RawMaterialButton,仅保留点击功能,可大幅降低该组件的绘制开销。
  • 必须使用RawMaterialButton的场景,手动关闭多余效果:设置elevation、highlightElevation、focusElevation均为0,splashColor、highlightColor设为透明,去掉所有冗余的视觉效果。
  • 给按钮包裹RepaintBoundary组件,让按钮的重绘区域和页面其他区域隔离,页面切换动画过程中不需要重复光栅化按钮部分的内容。

内容的提问来源于stack exchange,提问作者user6267530

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 21:21:01