Flutter 嵌套地狱?不存在的,ConstraintLayout 来解救!(五)

发布于 2022-7-7 17:09
浏览
0收藏

 

性能优化

1. 当布局复杂时,如果子元素需要频繁重绘,可以考虑使用 RepaintBoundary。当然合成 Layer 也有开销,所以需要合理使用。

class OffPaintExample extends StatelessWidget {
  const OffPaintExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ConstraintLayout(
          children: [
            Container(
              color: Colors.orangeAccent,
            ).offPaint().applyConstraint(
              width: 200,
              height: 200,
              topRightTo: parent,
            )
          ],
        ),
      ),
    );
  }
}


2. 尽量使用 const Widget。如果你没法将子元素声明为 const 而它自身又不会改变。可以使用内置的 OffBuildWidget 来避免子元素重复 build。

class OffBuildExample extends StatelessWidget {
  const OffBuildExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ConstraintLayout(
          children: [

            /// subtrees that do not change
            Container(
              color: Colors.orangeAccent,
            ).offBuild(id: 'id').applyConstraint(
              width: 200,
              height: 200,
              topRightTo: parent,
            )
          ],
        ),
      ),
    );
  }
}


3. 子元素会自动成为 RelayoutBoundary 除非它的宽或高是 wrapContent。可以酌情地减少 wrapContent 的使用,因为当 ConstraintLayout 自身的大小发生变化时(通常是窗口大小发生变化,移动端几乎不存在此类情况),所有宽或高为 wrapContent 的子元素都会被重新布局。而其他元素由于传递给它们的约束未发生变化,不会触发真正的布局。
4. 如果你在 children 列表中使用 Guideline 或 Barrier, Element 和 RenderObject 将不可避免的被创建,它们会被布局但不会绘制。此时你可以使用 GuidelineDefine 或 BarrierDefine 来优化, Element 和 RenderObject 就不会再创建了。

class BarrierExample extends StatelessWidget {
  const BarrierExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    ConstraintId leftChild = ConstraintId('leftChild');
    ConstraintId rightChild = ConstraintId('rightChild');
    ConstraintId barrier = ConstraintId('barrier');
    return Scaffold(
      body: ConstraintLayout(
        childConstraints: [
          BarrierDefine(
            id: barrier,
            direction: BarrierDirection.bottom,
            referencedIds: [leftChild, rightChild],
          ),
        ],
        children: [
          Container(
            color: const Color(0xFF005BBB),
          ).applyConstraint(
            id: leftChild,
            width: 200,
            height: 200,
            topLeftTo: parent,
          ),
          Container(
            color: const Color(0xFFFFD500),
          ).applyConstraint(
            id: rightChild,
            width: 200,
            height: matchConstraint,
            centerRightTo: parent,
            heightPercent: 0.5,
            verticalBias: 0,
          ),
          const Text(
            'Align to barrier',
            style: TextStyle(
              fontSize: 40,
              color: Colors.blue,
            ),
          ).applyConstraint(
            centerHorizontalTo: parent,
            top: barrier.bottom,
          )
        ],
      ),
    );
  }
} 


5. 每一帧,ConstraintLayout 会比对参数并决定以下事情:
1. 是否需要重新计算约束?
2. 是否需要重新布局?
3. 是否需要重新绘制?
4. 是否需要重排绘制顺序?
5. 是否需要重排事件分发顺序?
这些比对不会成为性能瓶颈,但会提高 CPU 占用率。如果你对 ConstraintLayout 内部原理足够了解,你可以使用 ConstraintLayoutController 来手动触发这些操作,停止参数比对。

class ConstraintControllerExampleState extends State<ConstraintControllerExample> {
  double x = 0;
  double y = 0;
  ConstraintLayoutController controller = ConstraintLayoutController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const CustomAppBar(
        title: 'Constraint Controller',
        codePath: 'example/constraint_controller.dart',
      ),
      body: ConstraintLayout(
        controller: controller,
        children: [
          GestureDetector(
            child: Container(
              color: Colors.pink,
              alignment: Alignment.center,
              child: const Text('box draggable'),
            ),
            onPanUpdate: (details) {
              setState(() {
                x += details.delta.dx;
                y += details.delta.dy;
                controller.markNeedsPaint();
              });
            },
          ).applyConstraint(
            size: 200,
            centerTo: parent,
            translate: Offset(x, y),
          )
        ],
      ),
    );
  }
}


扩展

ConstraintLayout 基于约束的布局算法极其强大和灵活,似乎可以成为了一个通用的布局框架。你只需要生成约束,将布局的任务交给 ConstraintLayout 即可。部分内置功能比如圆形定位、瀑布流、网格、列表以扩展的形式提供。

在线示例中的图表就是一个典型的扩展:

Flutter 嵌套地狱?不存在的,ConstraintLayout 来解救!(五)-开源基础软件社区

charts.gif

欢迎为 ConstraintLayout 开发扩展。

 

文章转自公众号:FlutterFirst

已于2022-7-7 17:09:03修改
收藏
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐