0%

Flutter 开发Tips (第一期)

延展操作符(...)可以对数组或者字典进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 合并数组
test1() {
var list = [1, 2, 3];
var list2 = [0, ...list, 4];
print(list2);
// [0, 1, 2, 3, 4]
}

// 合并字典
test2() {
var map1 = {
"key1": "value1",
"key2": "value2",
};
var map2 = {
"key3": "value3",
"key4": "value4",
};
var map3 = {...map1, ...map2};
print(map3);
// {key1: value1, key2: value2, key3: value3, key4: value4}
}

for ()…[]

合并widgets到集合中,使用for ()...[]范式,使用延展操作符(...)来合并一个数组的widgets到一个存在的集合中。例如在构造Row或者Column的children时,非常方便。下面是示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
List<Food> foods = [
Food(name: 'apple', isVegetarian: true),
Food(name: 'nuts', isVegetarian: true),
Food(name: 'eggs', isVegetarian: true),
Food(name: 'chicken', isVegetarian: false),
];

class Food {
Food({
this.name,
this.isVegetarian,
});

String name;
bool isVegetarian;
}

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

@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Container(),
for (final food in foods) ...[
if (food.isVegetarian) ListTile(title: Text(food.name)),
SizedBox(height: 50.0),
],
],
),
);
}

() {} ()

立即执行一个匿名函数:() {} (),相当于声明一个匿名函数并且里面执行,这种范式在处理一个widget可能有多种输出时特别有用。而不是使用镶嵌的三目运算符或者通过一个函数调用,这个代码跟内联。下面是示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
T getRandomElement<T>(List<T> list) => list[Random().nextInt(list.length)];

Column(
children: [
Container(
color: () {
switch (getRandomElement(foods).name) {
case 'apple':
return Colors.green;
case 'nuts':
return Colors.brown;
case 'eggs':
return Colors.yellow;
default:
return Colors.transparent;
}
}(),
child: Text('Food of the Day'),
),
],
)

代码静态分析

在提交代码时为了提高代码质量,保持团队的代码风格一致,需要进行代码静态分析,一般通过下面2种方法来进行

flutter analyze

使用flutter analyze进行代码静态分析,此命令会根据analysis_options.yaml定义的规则进行静态分析

dartfmt

使用dartfmt ./ -w对当前目录以及子目录的dart代码进行代码,-w选项会自动重写文件使其符合规范。

使用dartfmt ./ -n显示当前目录以及子目录的dart代码格式可以修改的文件但是不做修改,可以配合ci分析代码格式问题。

更多选项请使用dartfmt --help查看

Push & present & Pop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Push by route
Navigator.pushNamed(context, '/b')

// push
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => MyPage()));

// present
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => MyPage(),fullscreenDialog: true));

// pop
Navigator.pop(context)

// pop + push
Navigator.of(context)
..pop()
..pop()
..pushNamed('/settings');

API

1
2
3
4
5
6
7
8
9
// push
Future push(BuildContext context, Route route)

// pop
bool pop(BuildContext context, [ result ])

// 下面两种是等效的
Navigator.push(BuildContext context, Route route)
Navigator.of(context).push(Route route)

获取widget的位置和宽高

1
2
3
final RenderBox box = keyContext.findRenderObject();
final size = box.size;
final topLeftPosition = box.localToGlobal(Offset.zero);

See more

Model To JSON

json_serializable

  1. 引入

    1
    2
    3
    4
    5
    6
    7
    8
    dependencies:
    # Your other regular dependencies here
    json_annotation: ^2.0.0

    dev_dependencies:
    # Your other dev_dependencies here
    build_runner: ^1.0.0
    json_serializable: ^2.0.0
  2. 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import 'package:json_annotation/json_annotation.dart';

    // user.g.dart 将在我们运行生成命令后自动生成
    part 'user.g.dart';

    ///这个标注是告诉生成器,这个类是需要生成Model类的
    @JsonSerializable()

    class User{
    User(this.name, this.email);

    String name;
    String email;
    //不同的类使用不同的mixin即可
    factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
    Map<String, dynamic> toJson() => _$UserToJson(this);
    }
  3. 单次解析:flutter packages pub run build_runner build

  4. 持续集成:flutter packages pub run build_runner watch

  5. json_serializable 在线json转dart model工具

Built value

  1. 在线json转build value 模板工具 https://charafau.github.io/json2builtvalue/

  2. VSCode built value 插件

  3. Sample code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    // interface model
    import 'package:built_value/built_value.dart';

    part 'user.g.dart';

    abstract class User implements Built<User, UserBuilder> {
    String get name;
    @nullable
    String get nickname;
    User._();
    factory User([updates(UserBuilder b)]) = _$User;
    }

    // init
    var user1 = new User((b) => b
    ..name = 'John Smith'
    ..nickname = 'Joe');

    // update
    var user2 = user.rebuild((b) => b
    ..nickname = 'Jojo');

    // update
    var updatedStructuredData = structuredData.rebuild((b) => b
    ..user.update((b) => b
    ..name = 'Johnathan Smith')
    ..credentials.phone.update((b) => b
    ..country = Country.switzerland
    ..number = '555 01234 555'));


    // nested builders
    abstract class Node implements Built<Node, NodeBuilder> {
    @nullable
    String get label;
    @nullable
    Node get left;
    @nullable
    Node get right;
    Node._();
    factory Node([updates(NodeBuilder b)]) = _$Node;
    }

    // new or update
    var node = new Node((b) => b
    ..left.left.left.right.left.right.label = 'I’m a leaf!'
    ..left.left.right.right.label = 'I’m also a leaf!');
    var updatedNode = node.rebuild((b) => b
    ..left.left.right.right.label = 'I’m not a leaf any more!'
    ..left.left.right.right.right.label = 'I’m the leaf now!');

参考