Flutter 学习之旅(九) 基础控件 Containe
Container
这是一个组合控件, 看了一下他的源码可以用非常简单来描述,但是他在这种布局的表现就非常的复杂,先来看一下为什么说他非常简单
看一下他的build方法
@override
Widget build(BuildContext context) {
Widget current = child;
if (child == null && (constraints == null || !constraints.isTight)) {
current = LimitedBox(
maxWidth: 0.0,
maxHeight: 0.0,
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
);
}
if (alignment != null)
current = Align(alignment: alignment, child: current);
final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
if (effectivePadding != null)
current = Padding(padding: effectivePadding, child: current);
if (color != null)
current = ColoredBox(color: color, child: current);
if (decoration != null)
current = DecoratedBox(decoration: decoration, child: current);
if (foregroundDecoration != null) {
current = DecoratedBox(
decoration: foregroundDecoration,
position: DecorationPosition.foreground,
child: current,
);
}
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
if (margin != null)
current = Padding(padding: margin, child: current);
if (transform != null)
current = Transform(transform: transform, child: current);
if (clipBehavior != Clip.none) {
current = ClipPath(
clipper: _DecorationClipper(
textDirection: Directionality.of(context),
decoration: decoration
),
clipBehavior: clipBehavior,
child: current,
);
}
return current;
}
完全就是一层嵌套一层,做过前端的可能很多属性都知道怎么回事,但是这里面有几个属性还是有必要提及一下的,
constraints
constraints 这个是用来约束子布局的,如果Container 的子布局是一个Text (),但是Text()这个控件没有width 和height这两个属性,
就可以通过constraints 这个属性在父布局中设置
一般设置方法
constraints:BoxConstraints.expand(width:200, height:200)
alignment
在控件在Container中的对齐方式,经常用的有Alignment.center Alignment.left 等等
这里面有一个比较有意思的地方,就是Alignment这个类描述各个点在这个二位空间的位置,值(-1~1表示距离权重)
中心点为0,0,那么topleft 应该是(-1,-1) 而topright(1,-1),这个就是他的构造方法,自己好好想一下,其实还是很有意思的
/// The top left corner.
static const Alignment topLeft = Alignment(-1.0, -1.0);
/// The center point along the top edge.
static const Alignment topCenter = Alignment(0.0, -1.0);
/// The top right corner.
static const Alignment topRight = Alignment(1.0, -1.0);
/// The center point along the left edge.
static const Alignment centerLeft = Alignment(-1.0, 0.0);
/// The center point, both horizontally and vertically.
static const Alignment center = Alignment(0.0, 0.0);
/// The center point along the right edge.
static const Alignment centerRight = Alignment(1.0, 0.0);
/// The bottom left corner.
static const Alignment bottomLeft = Alignment(-1.0, 1.0);
/// The center point along the bottom edge.
static const Alignment bottomCenter = Alignment(0.0, 1.0);
/// The bottom right corner.
static const Alignment bottomRight = Alignment(1.0, 1.0);
decoration
这个其实就是android中drawable 配置文件设置背景的的方式,参数名都没怎么变,直接上例子,
decoration: BoxDecoration(
color: Colors.redAccent,/// 背景色 如果这里设置了color 外部就不能设置,否则报错
borderRadius: BorderRadius.all(Radius.circular(6)),/// 圆角
border: Border.all(color: Colors.black87, width: 2),///边框线 的颜色与宽度
gradient: LinearGradient(///渐变色 这里使用的是线性渐变
begin: Alignment.topLeft,
end: Alignment(0.5, 0.5),
// 10% of the width, so there are ten blinds.
colors: [Colors.redAccent, Colors.purpleAccent],
// whitish to gray
tileMode:
TileMode.repeated, // repeats the gradient over the canvas
),
boxShadow: <BoxShadow>[///阴影颜色
BoxShadow(
color: Colors.green,
offset: Offset(2, 2),
)
]),
decoration 中还能直接设置背景图片,使用image属性,我这里才用的线性渐变,就不用了,
这里面比较有意思的属性是 transform 这个属性,
看到了我给的是值是Matrix4.rotationZ(cos(60)) ,
![](https://img.haomeiwen.com/i11861448/ad46576223ca3a43.png)
这种旋转是围绕着z轴做选中,实际你看到的偏移量是x轴和y轴的距离做了偏移,看一下实际效果,
![](https://img.haomeiwen.com/i11861448/811b27eb99eba9b4.png)
我命名给的是Z轴旋转,为什么是x轴与y轴的的值发生了变化,看了上面那个旋转坐标系后才恍然大悟
最后再来说一下他为什么复杂,那是因为他的大小收子控件与对齐方式,还有父控件的大小等等很多因素干扰,
在源码的注释上面是这样提及的
If the widget has no child, no `height`, no `width`, no [constraints],
and the parent provides unbounded constraints, then [Container] tries to
size as small as possible.
If the widget has no child and no [alignment], but a `height`, `width`, or
[constraints] are provided, then the [Container] tries to be as small as
possible given the combination of those constraints and the parent's
constraints.
If the widget has no child, no `height`, no `width`, no [constraints], and
no [alignment], but the parent provides bounded constraints, then
[Container] expands to fit the constraints provided by the parent.
If the widget has an [alignment], and the parent provides unbounded
constraints, then the [Container] tries to size itself around the child.
If the widget has an [alignment], and the parent provides bounded
constraints, then the [Container] tries to expand to fit the parent, and
then positions the child within itself as per the [alignment].
Otherwise, the widget has a [child] but no `height`, no `width`, no
[constraints], and no [alignment], and the [Container] passes the
constraints from the parent to the child and sizes itself to match the
child.
这段话的意思大概就是
如果没有子布局、没有设置width、height以及constraints,并且父布局没有设置unbounded的限制,Container会将自身调整到足够小 (warp_centent)。
如果没有子布局、alignment,但是提供了width、height或者constraints,那么Container会根据自身以及父布局的限制,将自身调节到足够小。例如margin padding (warp_centent)
如果没有子布局、width、height、constraints以及alignment,但是父布局提供了bounded限制,那么Container会按照父布局的限制,将自身调整到足够大,直至填充满父布局的约束 (match_parent)。
如果有alignment,父布局提供了unbounded限制,那么Container将会调节自身尺寸来包住child 类似(warp_centent);
如果有alignment,并且父布局提供了bounded限制,那么Container会将自身调整的足够大(在父节点的范围内),然后将child根据alignment调整位置 (match_parent);
含有child,但是没有width、height、constraints以及alignment,Container会将父节点的constraints传递给child,并且根据child调整自身 (warp_centent)。
最后总结一下:
如果父布局添加了布局边界bounded的限制,则将会填充满父控件,否则将将按照内部子布局的约束来,
感觉这里还是有很多地方不是很理解,只能在接下来的使用过程中慢慢总结吧,
我学习flutter的整个过程都记录在里面了
https://www.jianshu.com/c/36554cb4c804
最后附上demo 地址