写代码容易,读代码难。功能是都实现了,但是对维护人员来说,简直就是灾难。
背景
Flutter
注重组合而非继承,要想搭建出 UI
,需要组合不同功能的 Widget
,如布局 Widget
、响应 Widget
、控件 Widget
等才能搭建出一个功能完善的 UI
界面,这便导致了嵌套地狱: 在顶级 Widget
的构造器中内嵌众多 Widget
。
像下面这个例子,其实都不是最多层的,只要你卖力,可以超乎想象的)))))))))))))))))).....
class FrostedGlass extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(
children: <Widget>[
new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: new FlutterLogo()),
new Center(
child: new ClipRect(
child: new BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Opacity(
opacity: 0.5,
child: new Container(
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: Colors.grey.shade200,
),
child: new Center(
child: new Text('Frosted',
style: Theme.of(context).textTheme.headline2),
),
),
),
),
),
),
],
),
);
}
}
在IDE
上面看到是这样的。
方法一
使用变量、方法与自定义 Widget
缓解嵌套地狱
// 把嵌套严重的 Widget 的一部分提出一个新的 Widget
class A xxxx {
// 使用方法抽离部分 Widget
Widget constructD() {
return new D(
child:new E(
child:new F(
child:new G(
...
),
),
),
),
}
@override
Widget build(BuildContext context) {
return new B(
child:new C(
child: constructD()
),
);
}
}
方法二
在widget
外面再包一层。请求自己的class
,返回封装好的widget
。使用时就是链式调用。
import 'package:flutter/material.dart';
///widget装饰器
class WidgetDecoration {
Widget _widget;
WidgetDecoration(Widget widget) {
this._widget = widget;
}
Function _onTapFunc;
Function _onDoubleTapFunc;
Function _onLongPressFunc;
///add padding属性
WidgetDecoration padding(
{Key key, double left = 0.0, double top = 0.0, double right = 0.0, double bottom = 0.0}) {
var padding = EdgeInsets.only(left: left, top: top, right: right, bottom: bottom);
_widget = new Padding(key: key, padding: padding, child: _widget);
return this;
}
///增加padingall
WidgetDecoration paddAll({Key key, double all = 0.0}) {
var padding = EdgeInsets.all(all);
_widget = new Padding(key: key, padding: padding, child: _widget);
return this;
}
///增加align 当前布局相对位置
///FractionalOffset.centerRight
WidgetDecoration align({Key key, AlignmentGeometry alignment = Alignment.center}) {
_widget = new Align(key: key, alignment: alignment, child: _widget);
return this;
}
///位置
WidgetDecoration positioned(
{Key key,
double left,
double top,
double right,
double bottom,
double width,
double height}) {
_widget = new Positioned(
key: key,
left: left,
top: top,
right: right,
bottom: bottom,
width: width,
height: height,
child: _widget);
return this;
}
///stack 相当于frameLayout布局
///填充布局
WidgetDecoration expanded({Key key, int flex = 1}) {
_widget = new Expanded(key: key, flex: flex, child: _widget);
return this;
}
///是否显示布局 true为不显示 false为显示
WidgetDecoration offstage({Key key, bool offstage = true}) {
_widget = new Offstage(key: key, offstage: offstage, child: _widget);
return this;
}
///透明度 0 是完全透明 1 完全不透明
WidgetDecoration opacity({Key key, @required double opacity, alwaysIncludeSemantics = false}) {
_widget = new Opacity(
key: key, opacity: opacity, alwaysIncludeSemantics: alwaysIncludeSemantics, child: _widget);
return this;
}
///基准线布局
WidgetDecoration baseline({
Key key,
@required double baseline,
@required TextBaseline baselineType,
}) {
_widget =
new Baseline(key: key, baseline: baseline, baselineType: baselineType, child: _widget);
return this;
}
///设置宽高比
WidgetDecoration aspectRatio({Key key, @required double aspectRatio}) {
_widget = new AspectRatio(key: key, aspectRatio: aspectRatio, child: _widget);
return this;
}
///矩阵转换
WidgetDecoration transform({
Key key,
@required Matrix4 transform,
origin,
alignment,
transformHitTests = true,
}) {
_widget = new Transform(
key: key,
transform: transform,
origin: origin,
alignment: alignment,
transformHitTests: transformHitTests,
child: _widget);
return this;
}
///居中 todo: center
WidgetDecoration center({Key key, double widthFactor, double heightFactor}) {
_widget =
new Center(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: _widget);
return this;
}
///布局容器
WidgetDecoration container({
Key key,
alignment,
padding,
Color color,
Decoration decoration,
foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
margin,
transform,
}) {
_widget = new Container(
key: key,
alignment: alignment,
padding: padding,
color: color,
decoration: decoration,
foregroundDecoration: foregroundDecoration,
width: width,
height: height,
constraints: constraints,
margin: margin,
transform: transform,
child: _widget);
return this;
}
///设置具体尺寸
WidgetDecoration sizedBox({Key key, double width, double height}) {
_widget = new SizedBox(key: key, width: width, height: height, child: _widget);
return this;
}
///设置最大最小宽高布局
WidgetDecoration constrainedBox({
Key key,
minWidth = 0.0,
maxWidth = double.infinity,
minHeight = 0.0,
maxHeight = double.infinity,
}) {
BoxConstraints constraints = new BoxConstraints(
minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight);
_widget = new ConstrainedBox(key: key, constraints: constraints, child: _widget);
return this;
}
///限定最大宽高布局
WidgetDecoration limitedBox({
Key key,
maxWidth = double.infinity,
maxHeight = double.infinity,
}) {
_widget = new LimitedBox(key: key, maxWidth: maxWidth, maxHeight: maxHeight, child: _widget);
return this;
}
///百分比布局
WidgetDecoration fractionallySizedBox(
{Key key, alignment = Alignment.center, double widthFactor, double heightFactor}) {
_widget = new FractionallySizedBox(
key: key,
alignment: alignment,
widthFactor: widthFactor,
heightFactor: heightFactor,
child: _widget);
return this;
}
///缩放布局
WidgetDecoration fittedBox({Key key, fit = BoxFit.contain, alignment = Alignment.center}) {
_widget = new FittedBox(key: key, fit: fit, alignment: alignment, child: _widget);
return this;
}
///旋转盒子 1次是90度
WidgetDecoration rotatedBox({
Key key,
@required int quarterTurns,
}) {
_widget = new RotatedBox(key: key, quarterTurns: quarterTurns, child: _widget);
return this;
}
///装饰盒子 细节往外抛 decoration 编写放在外面
WidgetDecoration decoratedBox({
Key key,
@required Decoration decoration,
position = DecorationPosition.background,
}) {
_widget =
new DecoratedBox(key: key, decoration: decoration, position: position, child: _widget);
return this;
}
///圆形剪裁
WidgetDecoration clipOval(
{Key key, CustomClipper<Rect> clipper, Clip clipBehavior = Clip.antiAlias}) {
_widget = new ClipOval(key: key, clipper: clipper, clipBehavior: clipBehavior, child: _widget);
return this;
}
///圆角矩形剪裁
WidgetDecoration clipRRect(
{Key key,
@required BorderRadius borderRadius,
CustomClipper<RRect> clipper,
Clip clipBehavior = Clip.antiAlias}) {
_widget = new ClipRRect(
key: key,
borderRadius: borderRadius,
clipper: clipper,
clipBehavior: clipBehavior,
child: _widget);
return this;
}
///矩形剪裁 todo: 需要自定义clipper 否则无效果
WidgetDecoration clipRect(
{Key key, @required CustomClipper<Rect> clipper, Clip clipBehavior = Clip.hardEdge}) {
_widget = new ClipRect(key: key, clipper: clipper, clipBehavior: clipBehavior, child: _widget);
return this;
}
///路径剪裁 todo: 需要自定义clipper 否则无效果
WidgetDecoration clipPath(
{Key key, @required CustomClipper<Path> clipper, Clip clipBehavior = Clip.antiAlias}) {
_widget = new ClipPath(key: key, clipper: clipper, clipBehavior: clipBehavior, child: _widget);
return this;
}
///animatedOpacity 淡入淡出
WidgetDecoration animatedOpacity({
Key key,
@required double opacity,
Curve curve = Curves.linear,
@required Duration duration,
}) {
_widget = new AnimatedOpacity(
key: key, opacity: opacity, curve: curve, duration: duration, child: _widget);
return this;
}
///页面简单切换效果
WidgetDecoration hero({Key key, @required Object tag}) {
_widget = new Hero(key: key, tag: tag, child: _widget);
return this;
}
///点击事件
WidgetDecoration onClick({Key key, onTap, onDoubleTap, onLongPress}) {
_widget = new GestureDetector(
key: key,
child: _widget,
onTap: onTap ?? _onTapFunc,
onDoubleTap: onDoubleTap ?? _onDoubleTapFunc,
onLongPress: onLongPress ?? _onLongPressFunc,
);
return this;
}
///添加点击事件
WidgetDecoration onTap(Function func, {Key key}) {
_onTapFunc = func;
_widget = new GestureDetector(
key: key,
child: _widget,
onTap: _onTapFunc,
onDoubleTap: _onDoubleTapFunc,
onLongPress: _onLongPressFunc,
);
return this;
}
///双击
WidgetDecoration onDoubleTap(Function func, {Key key}) {
_onDoubleTapFunc = func;
_widget = new GestureDetector(
key: key,
child: _widget,
onTap: _onTapFunc,
onDoubleTap: _onDoubleTapFunc,
onLongPress: _onLongPressFunc,
);
return this;
}
///长按
WidgetDecoration onLongPress(Function func, {Key key}) {
_onLongPressFunc = func;
_widget = new GestureDetector(
key: key,
child: _widget,
onTap: _onTapFunc,
onDoubleTap: _onDoubleTapFunc,
onLongPress: _onLongPressFunc,
);
return this;
}
Widget build() {
return _widget;
}
}
方法三
用扩展函数来给系统widget
添加一个child
属性。
使用时也支持链式调用。
extension WidgetExt on Widget {
Container intoContainer({
//复制Container构造函数的所有参数(除了child字段)
Key key,
AlignmentGeometry alignment,
EdgeInsetsGeometry padding,
Color color,
Decoration decoration,
Decoration foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
EdgeInsetsGeometry margin,
Matrix4 transform,
}) {
//调用Container的构造函数,并将当前widget对象作为child参数
return Container(
key: key,
alignment: alignment,
padding: padding,
color: color,
decoration: decoration,
foregroundDecoration: foregroundDecoration,
width: width,
height: height,
constraints: constraints,
margin: margin,
transform: transform,
child: this,
);
}
}