Flutter map 妙用及 .. 使用

4,570 阅读3分钟

前言

本篇文章对于熟悉 flutter 或者 dart 的小伙伴来说可能觉得比较简单,但是对于初学者或者没用过的小伙伴还是有些收获的。

背景

说到 map 妙用的发现,还要归功于 Tooltip 的研究。

在研究这个 Widget 的时候,看到了它的源码 demo,所以发现了这个 map 的妙用。

那么妙用在哪呢?

统一处理

我们在上节课说到了 Expanded 的比例布局。

源代码如下:

return Column(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.red,
          ),
        ),
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.blue,
          ),
        ),
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.grey,
          ),
        ),
      ],
    );

使用 map 可以转换为如下代码:

return Column(
      children: <Widget>[
        Container(
          color: Colors.red,
        ),
        Container(
          color: Colors.blue,
        ),
        Container(
          color: Colors.grey,
        ),
      ]
      //.map((Widget widget){ 也是可以的
      .map<Widget>((Widget widget){
          return Expanded(
            flex: 1,
            child: widget,
          );
      })
      .toList(),
    );

这样就统一管理了,减少了冗余代码,更加优雅了~

但是有时候可能我们有 10 个子组件,但是可能有 8 个需要统一处理,有两个不需要,怎么办呢?

我们可以利用 widget 的 标识属性 key 来处理。

以上面代码为例,假设我希望第一个子组件占两块比例,另外两个都占一块比例。

可以修改代码如下:

return Column(
      children: <Widget>[
        Container(
          key: Key('1'),
          color: Colors.red,
        ),
        Container(
          color: Colors.blue,
        ),
        Container(
          color: Colors.grey,
        ),
      ]
      //.map((Widget widget){ 也是可以的
      .map<Widget>((Widget widget){
        print(widget.key);
        int flex = 1;
        if (widget.key == Key('1')) {
          flex = 2;
        }
        return Expanded(
          flex: flex,
          child: widget,
        );
      })
      .toList(),
    );

可以看到我们通过 key 对第一个子组件做了区分处理。

另外正如学习设计模式的时候,不要为了设计而设计。
Map 的妙用能够使代码更优雅,但是我们也不要为了优雅而优雅。
而是真的适用你的场景,我们再使用。判别就是能否减少冗余代码。

其实上面的 map 用法有点让我想起 RxJava 里面 map 的使用。

我们可以认为上面的 map 是对一个列表里的每个元素按照特定规则进行处理。

.. Operator

.. 操作符在 dart 里面的描述是 cascade,翻译出来是级联。

这边的一个用法其实是链式写法。

什么意思呢?

我们举 StringBuffer 这个例子。

dart 里面的 StringBuffer 和 java 里面的 StringBuffer 是有差别的。

首先我们看下下面的字符串连接用 java 实现,代码如下:

		StringBuffer valueBuffer = new StringBuffer();
		valueBuffer.append("I")
				   .append(" ")
				   .append("love")
				   .append(" ")
				   .append("Flutter");
		System.out.println(valueBuffer.toString());

如果用 dart 实现的话,首先第一个点就是 dart 里面的 StringBuffer 没有 append 方法,取而代之的是 write 方法。

你以为只是上面的 append 改为 write?

如果你将 append 改为 write,如下

  StringBuffer valueBuffer = new StringBuffer();
  valueBuffer.write("I")
    .write(" ")
    .write("love")
    .write(" ")
    .write("Flutter");
  print(valueBuffer.toString());

编译器会提示下面错误:

The expression here has a type of 'void', and therefore cannot be used.

如果运行,也会报下面错误:

Error compiling to JavaScript:
DetailedApiRequestError(status: 400, message: main.dart:3:15:
Error: This expression has type 'void' and can't be used.
  valueBuffer.write("I")
              ^
main.dart:4:6:
Error: The method 'write' isn't defined for the class 'void'.
    .write(" ")
     ^^^^^
Error: Compilation failed.
)

很明显,write 方法返回类型是 void,因此不能这样写。

所以这个时候 .. 的作用就出现了,你只需要把 .append 改为 ..write 即可,如下:

  StringBuffer valueBuffer = new StringBuffer();
  valueBuffer..write("I")
    ..write(" ")
    ..write("love")
    ..write(" ")
    ..write("Flutter");
  print(valueBuffer.toString());

上面所有代码输出都是一样的,就是 I love Flutter

另外 Tooltip Demo 地址:👇
github.com/flutter/flu…

更多阅读:
Flutter 即学即用系列博客
Flutter 即学即用系列博客——01 环境搭建
Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
Flutter 即学即用系列博客——04 Flutter UI 初窥
Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
Flutter 即学即用系列博客——06 超实用 Widget 集锦
Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考

Flutter & dart
dart 如何优雅的避空