2019独角兽企业重金招聘Python工程师标准>>>
使用Flutter的视觉,结构,平台和交互式小部件集合更快地创建漂亮的应用程序。
基本部件
在构建您的第一个Flutter应用程序之前,您绝对需要了解这些小部件。
Container
一个方便的小部件,结合了常见的绘画,定位和尺寸小部件。
一个容器首先用padding包围子组件(由decoration中出现的所有边框填满),然后将附加constraints应用于填充范围(将width和height作为约束合并(如果其中任一个非空)。然后container被 margin描述的额外的空白空间包围。
在绘制过程中,容器首先应用给定的transform,然后绘制decoration来填满填充范围,然后绘制子组件,最后绘制foregroundDecoration,并填满填充范围。
没有子组件的容器尽可能大,除非传入的约束是无限的。在这种情况下,他们尽可能小,有子组件的容器将自己的尺寸扩大到他们的孩子大小,构造函数的宽度,高度和constraints参数将覆盖这些。
布局行为
有关Box布局模型的介绍,请参阅BoxConstraints(盒修饰)。
由于Container将许多其它部件与各自的布局行为结合在一起,因此Container的布局行为有点复杂。
Container按顺序尝试:遵守alignment,将自己调整到child部件的尺寸,遵守宽度,高度和constraints,扩展以适应父部件,变得尽可能小。
进一步来说:
如果部件没有子,没有height,没有width,没有constraints(对子部件的约束),父母提供了无界限的约束,那么Container尝试尽可能小。
如果部件没有子且没有alignment(对齐),但是提供了高度,宽度或constraints(约束),那么基于给定这些约束和父对象的约束相结合容器会尝试尽可能小。
如果小部件没有孩子,没有高度,没有宽度,没有约束,也没有对齐,但父级提供有界的约束,则Container展开以适应父级提供的约束。
如果部件具有alignment,并且父级提供了无界的约束,那么容器会尝试围绕该子部件调整自己的大小。
如果部件有alignment,并且父级提供了有界限的约束,那么容器会尝试展开以适合父级,然后根据alignment将该子级定位到其自身内。
另外,部件有一个子部件,但没有高度,没有宽度,没有约束,也没有对齐,并且容器将约束从父项传递给子项,并将其自身尺寸设置为与子部件匹配。
如这些属性的文档中所述,margin和padding属性也会影响布局。 (它们的效果只是丰富了上述规则。)decoration可以隐式强化填充(例如,BoxDecoration中的边框有助于填充); 请参阅Decoration.padding。
示例代码
这个例子显示了一个48x48的绿色正方形(放置在一个Center部件中,以防父容器对Container应该采用的尺寸有自己的看法),并带有一个边距,以便它远离相邻的小部件:
new Center(
child: new Container(
margin: const EdgeInsets.all(10.0),
color: const Color(0xFF00FF00),
width: 48.0,
height: 48.0,
),
)
此示例显示如何一次使用Container的许多功能。constraints被设置为适合字体大小加上充足的头部垂直空间,同时水平扩展以适合父母。padding用于确保内容和文本之间有空间。 颜色使箱子蓝绿色。alignment使得子部件被置于框中。foregroundDecoration将九个斑点的图像叠加到文本上。最后,transform对整个装置施加轻微旋转以完成效果。
new Container(
constraints: new BoxConstraints.expand(
height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
),
padding: const EdgeInsets.all(8.0),
color: Colors.teal.shade700,
alignment: Alignment.center,
child: new Text('Hello World', style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white)),
foregroundDecoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage('https://www.example.com/images/frame.png'),
centerSlice: new Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
),
),
transform: new Matrix4.rotationZ(0.1),
)
也可以看看:
- AnimatedContainer:一个变体,可以在属性更改时平滑地动画。
- Border,大量使用到Container。
- Ink,用于在Material上绘制装饰,允许InkResponse和InkWell飞溅来绘制它们。
- 布局部件的目录。
继承结构
Object>Diagnosticable>DiagnosticableTree>Widget>StatelessWidget>Container
构造器
Container({Key key, AlignmentGeometry alignment, EdgeInsetsGeometry padding, Color color, Decoration decoration, Decoration foregroundDecoration, double width, double height, BoxConstraints constraints, EdgeInsetsGeometry margin, Matrix4 transform, Widget child })
创建一个结合常见绘画,定位和尺寸小部件的小部件。[...]
属性
alignment → AlignmentGeometry
将容器内的子部件对齐。[...]
final
child → Widget
容器中包含的子部件。[...]
final
constraints → BoxConstraints
应用于子部件的附加限制。[...]
final
decoration → Decoration
绘制子部件背景装饰。[...]
final
foregroundDecoration → Decoration
绘制子部件前景装饰。
final
margin → EdgeInsetsGeometry
围绕装饰和子部件的空的区域。
final
padding → EdgeInsetsGeometry
在装饰里面刻写的空的区域。 子部件,如果有的话,被放置在这个填充。 [...]
final
transform → Matrix4
绘制容器之前应用的转换矩阵。
final
hashCode → int
此对象的哈希码. [...]
read-only, inherited
key → Key
控制一个部件如何替换树中的另一个部件。 [...]
final, inherited
runtimeType → Type
对象的运行时类型的表示。
read-only, inherited
方法
build(BuildContext context) → Widget
介绍由此部件代表的用户界面的一部分. [...]
debugFillProperties(DiagnosticPropertiesBuilder description) → void
createElement() → StatelessElement
创建一个StatelessElement来管理该小部件在树中的位置. [...]
inherited
debugDescribeChildren() → List
返回描述此节点的子节点的DiagnosticsNode对象的列表. [...]
@protected, inherited
noSuchMethod(Invocation invocation) → dynamic
当访问不存在的方法或属性时调用. [...]
inherited
toDiagnosticsNode({String name, DiagnosticsTreeStyle style }) → DiagnosticsNode
返回调试工具和toStringDeep使用的对象的调试表示形式. [...]
inherited
toString({DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回此对象的字符串表示形式.
inherited
toStringDeep({String prefixLineOne: '', String prefixOtherLines, DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回此节点及其后代的字符串表示形式. [...]
inherited
toStringShallow({String joiner: ',', DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回对象的单行详细描述. [...]
inherited
toStringShort() → String
这个部件的简短的文字描述.
inherited
操作符
operator ==(other) → bool
相等运算符. [...]
inherited
Row
在水平方向上布局子部件的列表。
一个以水平数组显示其子项的部件。
要让孩子展开以填充可用的水平空间,请将该孩子包裹在Expanded部件中。
Row部件不会滚动(并且一般认为在一行中有更多的孩子比适合可用的房间更好是错误的)。如果您有一行小部件,并希望它们在空间不足的情况下能够滚动,请考虑使用ListView。
对于垂直变体,请参见Column。
如果你只有一个子组件,那么考虑使用Align或Center来定位子组件。
示例代码
此示例将可用空间划分为三个(水平),并将文本居中放置在前两个单元格中,并将Flutter徽标放在第三个单元格中央:
new Row(
children: [
new Expanded(
child: new Text('Deliver features faster', textAlign: TextAlign.center),
),
new Expanded(
child: new Text('Craft beautiful UIs', textAlign: TextAlign.center),
),
new Expanded(
child: new FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: const FlutterLogo(),
),
),
],
)
疑难解答
为什么我的行有黄色和黑色的警告条纹?
如果该行的非弹性内容比该行(那些不包含在Expanded或Flexible部件中的)本身多,则该行被认为已经溢出。当一行溢出时,该行没有任何剩余空间Expanded和Flexible的子项。该行通过在溢出的边上绘制黄色和黑色条纹警告来报告此情况。如果行外有空间,溢出量将以红色字体打印。
故事时间
假设,例如,你有这样的代码:
new Row(
children: [
const FlutterLogo(),
const Text('Flutter\'s hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android.'),
const Icon(Icons.sentiment_very_satisfied),
],
)
该行首先询问其第一个子部件FlutterLogo布局,以任何尺寸标识。该徽标是友好的,愉快地决定一边24像素。这为下一个子部件留下了很多空间。该行然后询问下一个子部件,文本,它认为最好的尺寸布局。
在这一点上,不知道有多宽的文字会超出,说:“Ok, I will be thiiiiiiiiiiiiiiiiiiiis wide.”,并且远远超出了该行可用的空间,而不是包裹。行反应,“That's not fair, now I have no more room available for my other children!”,并生气发芽,黄色和黑色的条幅。
解决方法是将第二个孩子包装在Expanded部件中,该部件告诉行该子部件应该给予剩余房间:
new Row(
children: [
const FlutterLogo(),
const Expanded(
child: const Text('Flutter\'s hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android.'),
),
const Icon(Icons.sentiment_very_satisfied),
],
)
现在,该行首先要求logo布局,然后要求该icon布局。象标志一样,Icon很乐意采用合理的尺寸(也是24像素,并非巧合,因为FlutterLogo和Icon都符合环境IconTheme)。这留下了一些空间,现在该行告诉文本究竟有多宽:剩余空间的确切宽度。该文本现在很乐意遵守合理的请求,将文本包装在该宽度内,并且最终将一段文字分成几行。
布局算法
本节介绍框架如何渲染Row。 有关Box布局模型的介绍,请参阅BoxConstraints。
一行的布局分六步进行:
- 为每个孩子设置一个Null或0个弹性因子(例如,那些没有扩大的因子),其中包含无界的水平约束和传入的垂直约束。如果crossAxisAlignment是CrossAxisAlignment.stretch,则应使用与输入最大高度相匹配的严格垂直约束。
- 根据弹性因子,划分非零弹性因子(例如,Expanded)中的剩余水平空间。例如,弹性系数为2.0的孩子将获得两倍于水平空间的弹性系数为1.0的孩子。
- 使用与步骤1相同的垂直约束布局每个剩余的子项,但不是使用无界的水平约束,而是使用基于步骤2中分配的空间量的水平约束。具有FlexFit.tight的Flexible.fit属性的孩子被给予严格的约束(即,被迫填充分配的空间),并且具有FlexFit.loose的Flexible.fit属性的孩子被给予宽松的约束(即,不被迫填充 分配空间)。
- Row的高度是子部件的最大高度(这将始终满足传入的垂直约束)。
- 行的宽度由mainAxisSize属性确定。如果mainAxisSize属性是MainAxisSize.max,则Row的宽度是传入约束的最大宽度。 如果mainAxisSize属性是MainAxisSize.min,则Row的宽度是子级宽度的总和(受到传入约束的限制)。
- 根据mainAxisAlignment和crossAxisAlignment确定每个子部件的位置。例如,如果mainAxisAlignment是MainAxisAlignment.spaceBetween,所有未分配给子部件的水平空间均匀划分并放置在子部件之间。
也可以看看:
- Column,垂直等效。
- Flex,如果您事先不知道是否需要水平或垂直布置。
- Expanded,以表明子部件应该使用所有剩余房间。
- Flexible,指示子部件应该共享剩余房间,但可能小一些(留下一些剩余房间未使用)。
- 布局部件的目录。
继承结构
Object>Diagnosticable>DiagnosticableTree>Widget>RenderObjectWidge>MultiChildRenderObjectWidget>Flex>Row
构造函数
Row({Key key, MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, MainAxisSize mainAxisSize: MainAxisSize.max, CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, TextBaseline textBaseline, List
创建一个水平的子部件数组。[...]
属性
children → List
树中的部件下面的部件. [...]
final, inherited
crossAxisAlignment → CrossAxisAlignment
子部件应该如何沿着横轴放置. [...]
final, inherited
direction → Axis
用作主轴的方向. [...]
final, inherited
hashCode → int
此对象的哈希码. [...]
read-only, inherited
key → Key
控制一个部件如何替换树中的另一个部件. [...]
final, inherited
mainAxisAlignment → MainAxisAlignment
子部件应该如何沿主轴放置. [...]
final, inherited
mainAxisSize → MainAxisSize
在主轴上应占多少空间. [...]
final, inherited
runtimeType → Type
对象的运行时类型的表示.
read-only, inherited
textBaseline → TextBaseline
如果根据他们的基线对齐条目,使用哪个基线.
final, inherited
textDirection → TextDirection
确定水平放置子部件的顺序以及如何解释水平方向的开始和结束. [...]
final, inherited
verticalDirection → VerticalDirection
确定垂直放置子部件的顺序以及如何解释垂直方向的开始和结束. [...]
final, inherited
方法
createElement() → MultiChildRenderObjectElement
RenderObjectWidgets总是膨胀为一个RenderObjectElement子类.
inherited
createRenderObject(BuildContext context) → RenderFlex
使用RenderObjectWidget描述的配置创建此RenderObjectWidget表示的RenderObject类的实例 . [...]
inherited
debugDescribeChildren() → List
返回描述此节点的子节点的DiagnosticsNode对象的列表. [...]
@protected, inherited
debugFillProperties(DiagnosticPropertiesBuilder description) → void
inherited
didUnmountRenderObject(RenderObject renderObject) → void
先前与此部件关联的呈现对象已从树中移除。 给定的RenderObject将与此对象的createRenderObject返回的类型相同.
@protected, inherited
getEffectiveTextDirection(BuildContext context) → TextDirection
传给RenderFlex.textDirection的值. [...]
@protected, inherited
noSuchMethod(Invocation invocation) → dynamic
当访问不存在的方法或属性时调用. [...]
inherited
toDiagnosticsNode({String name, DiagnosticsTreeStyle style }) → DiagnosticsNode
返回调试工具和toStringDeep使用的对象的调试表示形式. [...]
inherited
toString({DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回此对象的字符串表示形式.
inherited
toStringDeep({String prefixLineOne: '', String prefixOtherLines, DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回此节点及其后代的字符串表示形式. [...]
inherited
toStringShallow({String joiner: ', ', DiagnosticLevel minLevel: DiagnosticLevel.debug }) → String
返回对象的单行详细描述. [...]
inherited
toStringShort() → String
这个部件的简短的文字描述.
inherited
updateRenderObject(BuildContext context, RenderFlex renderObject) → void
将此RenderObjectWidget描述的配置复制到给定的RenderObject,该RenderObject与该对象的createRenderObject返回的类型相同 . [...]
inherited
操作符
operator ==(other) → bool
等值操作符. [...]
inherited
Column
以垂直阵列显示其子项的部件。
要让子部件扩大以填充可用的垂直空间,请将该子部件包装在Expanded部件中。
Column部件不滚动(并且通常认为宁愿在列中有更多子项也不使用适合可用空间是错误的)。 如果您有一行小部件,并希望它们在空间不足的情况下能够滚动,请考虑使用ListView。
对于水平变体,请参见Row。
如果只有一个子部件,那么考虑使用Align或Center来定位子部件。
示例代码
这个例子使用一个Column垂直排列三个部件,最后一个用来填充所有剩余的空间。
new Column(
children: [
new Text('Deliver features faster'),
new Text('Craft beautiful UIs'),
new Expanded(
child: new FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: const FlutterLogo(),
),
),
],
)
在上面的示例中,text和logo位于每行的中心。在以下示例中,crossAxisAlignment设置为CrossAxisAlignment.start,以便子部件左对齐。mainAxisSize被设置为MainAxisSize.min,以便该列缩小以适合子部件。
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
new Text('We move under cover and we move as one'),
new Text('Through the night, we have one shot to live another day'),
new Text('We cannot let a stray gunshot give us away'),
new Text('We will fight up close, seize the moment and stay in it'),
new Text('It’s either that or meet the business end of a bayonet'),
new Text('The code word is ‘Rochambeau,’ dig me?'),
new Text('Rochambeau!', style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 2.0)),
],
)
故障排除
当传入的垂直约束是无界的时候
当一个列有一个或多个Expanded或Flexible的子元素,并且被放置在另一列,或者在一个ListView中,或者在其它没有为该列提供最大高度限制的上下文中时,你会在运行时说这个异常存在弹性子部件,但垂直约束是无界的。
这个例外所伴随的细节中所描述的问题是,使用Flexible或Expanded意味着在布置所有其他子部件之后的剩余空间必须平等地共享,但是如果传入的垂直约束是无限的,则剩余空间有无限空间。
解决这个问题的关键通常是确定为什么Column正在接收无界的垂直约束。
发生这种情况的一个常见原因是列已被放置在另一列中(没有使用Expanded或Flexible围绕内部嵌套列)。当一个列布局它的非柔性子部件(那些既没有 Expanded也没有Flexible包裹的子部件)时,它给了他们无限的约束,以便他们可以确定他们自己的尺寸(传递无界的约束通常指示子部件应该收缩包裹其内容)。在这种情况下,解决方案通常只是将内部列包装在Expanded中,以表明它应该占用外部列的剩余空间,而不仅仅是它需要的空间。
显示此消息的另一个原因是将列嵌套到ListView或其他垂直滚动条中。在这种情况下,确实存在无限的垂直空间(垂直滚动列表的整个点是允许垂直无限空间)。在这种情况下,通常值得研究内部列为什么应该有一个Expanded或Flexible的子部件:内部子部件应该是多大?这种情况下的解决方案通常是从内部子部件周围移除Expanded或Flexible部件。
有关约束的更多讨论,请参阅BoxConstraints。
黄色和黑色的条纹横幅
当列的内容超过可用空间量时,列溢出,内容被剪辑。 在调试模式下,在溢出边缘处呈现黄色和黑色条纹条以指示问题,并在列下方显示一条消息,指出检测到多少溢出。
通常的解决方案是使用ListView而不是Column来在垂直空间有限时使内容滚动。
布局算法
本节介绍框架如何呈现一列。 有关Box布局模型的介绍,请参阅BoxConstraints。
一列的布局分六步进行:
- 为每个孩子设置一个null或零个弹性因子(例如那些没有Expanded的部件)和无限制的垂直约束和传入水平约束。如果crossAxisAlignment是CrossAxisAlignment.stretch,请使用与输入最大宽度匹配的严格的水平约束。
- 根据弹性因子,在非零弹性因子的子部件(例如扩展)中划分剩余的垂直空间。 例如,弹性系数为2.0的子部件将获得弹性系数为1.0的子部件的两倍的垂直空间量。
- 使用与步骤1中相同的水平约束来布局每个剩余的子项,但不是使用无界的垂直约束,而是使用基于步骤2中分配的所有空间的垂直约束。Flexible.fit属性是FlexFit.tight严格约束的子项(即,被迫填充分配的空间),并且具有FlexFit.loose的Flexible.fit属性的孩子被给予宽松的约束(即,不被迫填充分配的空间)。
- Column的宽度是子部件的最大宽度(这将始终满足传入的水平约束)。
- 列的高度由mainAxisSize属性确定。如果mainAxisSize属性为MainAxisSize.max,那么Column的高度就是传入约束的最大高度。如果mainAxisSize属性为MainAxisSize.min,那么Column的高度就是子级高度的总和(受传入约束条件的影响)。
- 根据mainAxisAlignment和crossAxisAlignment确定每个子部件的位置。例如,如果mainAxisAlignment是MainAxisAlignment.spaceBetween,则所有尚未分配给子部件的垂直空间均匀划分并放置在子部件之间。
也可以看看:
- Column,垂直等效。
- Flex,如果您事先不知道是否需要水平或垂直布置。
- Expanded,以表明子部件应该使用所有剩余房间。
- Flexible,指示子部件应该共享剩余房间,但可能小一些(留下一些剩余房间未使用)。
- 布局部件的目录。
继承结构
Object>Diagnosticable>DiagnosticableTree>Widget>RenderObjectWidget>MultiChildRenderObjectWidget>Flex>Column
构造函数
Column({Key key, MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, MainAxisSize mainAxisSize: MainAxisSize.max, CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, TextBaseline textBaseline, List
创建一个垂直的子部件数组. [...]
属性,方法,操作符
同Row