在APP
开发过程中,经常遇到需要添加背景、设置边距、动态显示和隐藏某个组件。
但是在Flutter
中,能同时具有添加背景、设置边距、阴影、边框、圆角的布局只有Container
(参考我上一篇文章的介绍Flutter入门之Row、Column、Container布局),这个已经算是业务功能比较多的组件了,而要想实现组件的显示和隐藏则需要用到另外一个组件Offstage
,水平的线性布局则需要用到组件Row
,垂直的线性布局则需要用到组件Column
,而Row
和Column
这两个布局都不具备直接设置背景、边距、显示和隐藏等功能。
在开发过程中这种需求又很常见,不可能每个地方都把这些代码重复一遍,所以对这几个组件封装一下,实现了一个类似Android
中LinearLayout
布局的组件很有必要。
封装成LinearLayout
其实很简单,就是将Row
、Column
、Offstage
、Container
四个组件合理的组合在一起就可以了。
Container
经常用到的背景、边距参数暴露出来Row
、Column
中用到的主轴、交叉轴的对齐方式暴露出来Row
、Column
中主轴size的适配方式暴露出来代码如下:
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 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 [],
this.mainAxisAlignment = MainAxisAlignment.start,
this.mainAxisSize = MainAxisSize.min,
this.crossAxisAlignment = CrossAxisAlignment.center,
}) : super(key: key);
@override
LinearLayoutState createState() {
return LinearLayoutState();
}
}
class LinearLayoutState extends State {
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文件代码如下:
bool isNull(dynamic obj) {
return obj == null;
}
bool isNotNull(dynamic obj) {
return obj != null;
}
class LinearLayoutSampleWidget extends StatefulWidget {
@override
State createState() {
return LinearLayoutSampleState();
}
}
class LinearLayoutSampleState extends State {
GlobalKey _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LinearLayout Sample'),
),
body:
LinearLayout(
background: BoxDecoration(color: Colors.blue),
orientation: LayoutOrientation.vertical,
children: [
LinearLayout(
key: _key,
background: BoxDecoration(color: Colors.red),
orientation: LayoutOrientation.horizontal,
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.list),
Text('线性布局')
],
),
FlatButton(
onPressed: () {
bool isVisible = _key.currentState.isVisible();
_key.currentState.setVisible(!isVisible);
},
child: Text('切换显示'),
)
],
)
);
}
}
这里重点说一下Demo中的GlobalKey
这段代码,这个就是用来给LinearLayout
设定一个唯一标识符,这样才能在后面点击按钮的时候调用setVisible
方法来显示和隐藏。而泛型LinearLayoutState
则是我封装的代码中的一个类,因为我的setVisible
方法暴露在此State中。
下面是我的个人公众号,欢迎关注交流