Flutter实战之封装一个LinearLayout

APP开发过程中,经常遇到需要添加背景、设置边距、动态显示和隐藏某个组件。

但是在Flutter中,能同时具有添加背景、设置边距、阴影、边框、圆角的布局只有Container(参考我上一篇文章的介绍Flutter入门之Row、Column、Container布局),这个已经算是业务功能比较多的组件了,而要想实现组件的显示和隐藏则需要用到另外一个组件Offstage,水平的线性布局则需要用到组件Row,垂直的线性布局则需要用到组件Column,而RowColumn这两个布局都不具备直接设置背景、边距、显示和隐藏等功能。

在开发过程中这种需求又很常见,不可能每个地方都把这些代码重复一遍,所以对这几个组件封装一下,实现了一个类似AndroidLinearLayout布局的组件很有必要。

封装LinearLayout

封装成LinearLayout其实很简单,就是将RowColumnOffstageContainer四个组件合理的组合在一起就可以了。

  1. 首先要暴露一个参数确定是水平的线性布局还是垂直的线性布局
  2. Container经常用到的背景、边距参数暴露出来
  3. RowColumn中用到的主轴、交叉轴的对齐方式暴露出来
  4. RowColumn中主轴size的适配方式暴露出来
  5. 暴露出一个方法用来动态改变组件的显示和隐藏

代码如下:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import 'package:flutter/material.dart';
import 'package:flutter_library/common/util.dart';

enum LayoutOrientation { horizontal, vertical }

class LinearLayout extends StatefulWidget {
final LayoutOrientation orientation;
final bool isVisible;
final Decoration background;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry margin;
final List<Widget> children;

final MainAxisAlignment mainAxisAlignment;
final MainAxisSize mainAxisSize;
final CrossAxisAlignment crossAxisAlignment;

LinearLayout({
Key key,
this.orientation,
this.isVisible = true,
this.background,
this.padding,
this.margin,
this.children = const <Widget>[],
this.mainAxisAlignment = MainAxisAlignment.start,
this.mainAxisSize = MainAxisSize.min,
this.crossAxisAlignment = CrossAxisAlignment.center,
}) : super(key: key);

@override
LinearLayoutState createState() {
return LinearLayoutState();
}
}

class LinearLayoutState extends State<LinearLayout> {
bool _isVisible = true;

@override
void initState() {
_isVisible = widget.isVisible;
super.initState();
}

@override
Widget build(BuildContext context) {
return isNotNull(_isVisible)
? Offstage(
offstage: !_isVisible,
child: _buildLayoutWidget(),
)
: _buildLayoutWidget();
}

Widget _buildLayoutWidget() {
if (_isNeedContainerWidget()) {
return _buildContainerWidget();
} else {
return _buildOrientationWidget();
}
}

bool _isNeedContainerWidget() {
return isNotNull(widget.background) ||
isNotNull(widget.padding) ||
isNotNull(widget.margin);
}

Widget _buildContainerWidget() {
return Container(
decoration: widget.background,
padding: widget.padding,
margin: widget.margin,
child: _buildOrientationWidget(),
);
}

Widget _buildOrientationWidget() {
if (widget.orientation == LayoutOrientation.horizontal) {
return _buildHorizontalWidget();
} else {
return _buildVerticalWidget();
}
}

Widget _buildVerticalWidget() {
return Column(
mainAxisSize: widget.mainAxisSize,
mainAxisAlignment: widget.mainAxisAlignment,
crossAxisAlignment: widget.crossAxisAlignment,
children: widget.children,
);
}

Widget _buildHorizontalWidget() {
return Row(
mainAxisSize: widget.mainAxisSize,
mainAxisAlignment: widget.mainAxisAlignment,
crossAxisAlignment: widget.crossAxisAlignment,
children: widget.children,
);
}

bool isVisible() {
return _isVisible;
}

void setVisible(bool isVisible) {
setState(() {
_isVisible = isVisible;
});
}
}

package:flutter_library/common/util.dart文件代码如下:

1
2
3
4
5
6
7
bool isNull(dynamic obj) {
return obj == null;
}

bool isNotNull(dynamic obj) {
return obj != null;
}

LinearLayout使用

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
class LinearLayoutSampleWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return LinearLayoutSampleState();
}
}

class LinearLayoutSampleState extends State<LinearLayoutSampleWidget> {
GlobalKey<LinearLayoutState> _key = GlobalKey<LinearLayoutState>();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LinearLayout Sample'),
),
body:
LinearLayout(
background: BoxDecoration(color: Colors.blue),
orientation: LayoutOrientation.vertical,
children: <Widget>[
LinearLayout(
key: _key,
background: BoxDecoration(color: Colors.red),
orientation: LayoutOrientation.horizontal,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(Icons.list),
Text('线性布局')
],
),
FlatButton(
onPressed: () {
bool isVisible = _key.currentState.isVisible();
_key.currentState.setVisible(!isVisible);
},
child: Text('切换显示'),
)
],
)
);
}
}

这里重点说一下Demo中的GlobalKey<LinearLayoutState> _key = GlobalKey<LinearLayoutState>()这段代码,这个就是用来给LinearLayout设定一个唯一标识符,这样才能在后面点击按钮的时候调用setVisible方法来显示和隐藏。而泛型LinearLayoutState则是我封装的代码中的一个类,因为我的setVisible方法暴露在此State中。


原创文章,转载请出处注明。

下面是我的个人公众号,欢迎关注交流

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×