Android当中,一切都是View。布局类View称为ViewGroup。Flutter当中,一切都是Widget。
而根据Widget是否须要包含子节点将Widget分为了三类:数组
而咱们在前文中也提到过,Element树才是最终的绘制树,Element树是经过widget树来建立的(经过Widget.createElement()
),widget其实就是Element的配置数据。
Flutter中,根据Widget是否须要包含子节点将Widget分为了三类,分别对应三种Element,以下表:bash
Widget | 对应的Element | 用途 |
---|---|---|
LeafRenderObjectWidget | LeafRenderObjectElement | Widget树的叶子节点,用于没有子节点的widget,一般基础widget都属于这一类,如Text、Image。 |
SingleChildRenderObjectWidget | SingleChildRenderObjectElement | 包含一个子Widget,如:ConstrainedBox、DecoratedBox等 |
MultiChildRenderObjectWidget | MultiChildRenderObjectElement | 包含多个子Widget,通常都有一个children参数,接受一个Widget数组。如Row、Column、Stack等 |
注意,Flutter中的不少Widget是直接继承自StatelessWidget或StatefulWidget,而后在build()方法中构建真正的RenderObjectWidget,如Text,它实际上是继承自StatelessWidget,而后在build()方法中经过RichText来构建其子树,而RichText才是继承自LeafRenderObjectWidget。因此为了方便叙述,咱们也能够直接说Text属于LeafRenderObjectWidget(其它widget也能够这么描述),这才是本质。读到这里咱们也会发现,其实StatelessWidget和StatefulWidget就是两个用于组合Widget的基类,它们自己并不关联最终的渲染对象(RenderObjectWidget)。less
与原生开发中“控件”不一样的是,Flutter中的widget的概念更普遍,它不只能够表示UI元素,也能够表示一些功能性的组件如:用于手势检测的 GestureDetector widget、用于应用主题数据传递的Theme等等。
这里特指直接呈现UI的widget,好比文本、按钮、图片、Icon、输入框表单等等。
好比,Material widget库中提供了多种按钮Widget如RaisedButton、FlatButton。全部Material 库中的按钮都有以下相同点:布局
RaisedButton(
child: Text("normal"),
onPressed: () => {},
),
FlatButton(
child: Text("normal"),
onPressed: () => {},
),
OutlineButton(
child: Text("normal"),
onPressed: () => {},
),
IconButton(
icon: Icon(Icons.send),
onPressed: () => {},
),
FlatButton(
child: Text("Submit"),
color: Colors.blue,
highlightColor: Colors.blue[700],
colorBrightness: Brightness.dark,
textColor: Colors.white,
padding: EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius : BorderRadius.circular(20)
),
splashColor: Colors.grey,
onPressed: (){},
),
复制代码
对应的效果以下: 动画
直接或间接继承(包含)MultiChildRenderObjectWidget的Widget,它们通常都会有一个children属性用于接收子Widget。 好比 线性布局Row和Column、弹性布局Flex、流式布局Wrap、Flow、层叠布局Stack、Positioned等。 这里以Wrap举例。Flutter中,子widget超出屏幕范围,则会报溢出错误。
ui
Wrap({
...
this.direction = Axis.horizontal,
this.alignment = WrapAlignment.start,
this.spacing = 0.0,
this.runAlignment = WrapAlignment.start,
this.runSpacing = 0.0,
this.crossAxisAlignment = WrapCrossAlignment.start,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
List<Widget> children = const <Widget>[],
})
复制代码
样例代码以下:this
Wrap(
spacing: 8.0, // 主轴(水平)方向间距
runSpacing: 4.0, // 纵轴(垂直)方向间距
alignment: WrapAlignment.center, //沿主轴方向居中
children: <Widget>[
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('A')),
label: new Text('Hamilton'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('M')),
label: new Text('Lafayette'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('H')),
label: new Text('Mulligan'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('J')),
label: new Text('Laurens'),
),
],
)
复制代码
效果以下图: spa
直接或间接继承(包含)SingleChildRenderObjectWidget的Widget,它们通常都会有一个child属性用于接收子Widget。 这一类的widget有Padding、ConstrainedBox、DecoratedBox等。3d
容器类Widget和布局类Widget都做用于其子Widget,不一样的是:code
布局类Widget通常都须要接收一个widget数组(children),他们直接或间接继承自(或包含)MultiChildRenderObjectWidget.
布局类Widget是按照必定的排列方式来对其子Widget进行排列;
容器类Widget通常只须要接收一个子Widget(child),他们直接或间接继承自(或包含)SingleChildRenderObjectWidget。
容器类Widget通常只是包装其子Widget,对其添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)。
更多widget了解能够跳转这里
若是你以为这篇文章对你有益,还请帮忙转发和点赞,万分感谢。