今天看啥  ›  专栏  ›  oldbirds

Flutter 不显示任何内容,返回哪个Widget 合适?

oldbirds  · 掘金  ·  · 2021-03-22 08:37
阅读 13

Flutter 不显示任何内容,返回哪个Widget 合适?

当您不想显示任何内容时,我们通常做法是返回Container 或者SizedBox,但是这是最佳方案么?

return Builder(
  builder: (_) {
    if (condition) {
      return const MyWidget();
    } else {
      return const Container();
      // return const SizedBox();
    }
  },
);
复制代码

我们都知道 Flutter 的四棵树:Widget 树,Element 树, RenderObject 树和 Layer 树。

  1. 当应用启动时,会遍历并创建所有的 Widget 形成 Widget Tree。
  2. 同时与 Widget Tree 相对应,通过调用 Widget 上的 createElement() 方法创建每个 Element 对象,形成 Element Tree。
  3. 当每个 Element 调用 createRenderObject() 时,将创建对应渲染对象,形成一个 Render Tree。
  4. Layer 的组成由 RenderObject 中的 isRepaintBoundary 标志位决定,当 isRepaintBoundary 为 true 时,那么该区域就是一个可更新绘制区域,而当这个区域形成时,其实就会新创建一个 Layer,而由 Layer 构成的 Layer Tree 最后会被提交到 Flutter Engine 绘制出画面。

RenderObject 它才是真正干活(layout、paint)。所以如果我们想要不显示任何内容,那么返回的 Widget 应该不需要在屏幕绘制出来。也就是说当你返回 Container 或者 SizedBox 也不是最佳方案,因为它们也会创建对应的 RenderObject,RenderObject 位于渲染树中,虽然在屏幕上不显示任何内容,也对其进行一些计算。

如果有个 Widget 不创建 RenderObject 就好了。

很高兴的告诉你,还真有个 Widget 适合这种情况,它不是官方提供的。这个 Widget 就是 nil

nil 的实现非常简单:

import 'package:flutter/widgets.dart';

/// 一个 [Nil] 实例, 可以用在你的布局中.
const nil = Nil();

/// 这个 Widget 不做任何事情.
/// 当你要返回个 Widget 但又不能返回 null 的时候,非常适合.
class Nil extends Widget {
  /// Creates a [Nil] widget.
  const Nil({Key? key}) : super(key: key);

  @override
  Element createElement() => _NilElement(this);
}

class _NilElement extends Element {
  _NilElement(Nil widget) : super(widget);

  @override
  bool get debugDoingBuild => false;

  @override
  void performRebuild() {}
}
复制代码

Nil 自定义了 _NilElement,在 _NilElement 我们没有看到 RenderObject 的创建。

那么如何使用?

nil: ^1.0.1
复制代码

我们验证下是有 RenderObject 创建

class MyPage extends StatelessWidget {
  final bool showText;

  MyPage({this.showText});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text('hello, oldbirds'),
          showText ? Text('Container') : Container(),
          showText ? Text('nil') : Nil(),
        ],
      ),
    );
  }
}
复制代码

我们可以非常清晰的观察到 Container 还是比较复杂的,也看到了 RenderObject 的创建。与之对比,Nil 就非常的干净,啥都没有。

从四棵树的理论来说,Nil 在这里比会比 Container、SizedBox 等更适合。

注意

This widget is not intended to be used in widgets accepting multiple children (e.g. Rows, Columns, etc.). The best option is to not add a widget in the list if you don't want it to be displayed. Moreover using a Nil widget in such a case, can have unexpected results.

所以在 Columns 的地方不建议使用,本例子只是为了更好的对比才这样写的。更好的做法:

class MyPage extends StatelessWidget {
  final bool showText;

  MyPage({this.showText});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text('hello, oldbirds'),
          if(showText) Text('Container'),
          if(showText) Text('nil'),
        ],
      ),
    );
  }
}
复制代码

如果想加入Flutter微信交流群,请关注官方微信公众号 OldBirds




原文地址:访问原文地址
快照地址: 访问文章快照