1. Column
Column 是一个小部件,可在列上显示其子小部件。另一个变体是 Row,它在一行上显示其子部件。
- Flutter Row
要使 Column 的子小部件扩展以填充可用的垂直空间,可以将其包装在 Expanded 对象中。 - Flutter Expanded
Column 会将其子项放在一列上并且不能滚动。如果想要一个类似的和可滚动的容器,应该考虑使用 ListView。
Column 构造函数:
Column(
{Key key,
List<Widget> children: const <Widget>[],
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start,
MainAxisSize mainAxisSize: MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection: VerticalDirection.down,
TextBaseline textBaseline
}
)
2. children
children 属性用于定义 Column 的子小部件列表。
可以向子项添加子窗口小部件,或从子项中删除窗口小部件,但必须遵循“添加/删除子项”部分中提到的规则。
List<Widget> children: const <Widget>[]
下面来看看第一个示例,一个带有四个子小部件的 Column:
代码文件:main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'yiibai.com',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Column Example")
),
body: Center(
child: Column (
children: [
ElevatedButton(child: Text("Button 1"), onPressed:(){}),
Icon(Icons.ac_unit, size: 48, color: Colors.blue),
ElevatedButton(
child: Text("Button 2"),
onPressed:(){},
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(Size.square(70))
)
),
ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}),
]
)
),
);
}
}
一些 flex > 0
的子部件可以扩展其高度以垂直填充剩余空间,例如 Expanded、Spacer 等。它们通常用于调整 Column 的子部件之间的距离。例子:
示例代码:
Column (
children: [
ElevatedButton(child: Text("Button 1"), onPressed:(){}),
Expanded (
flex: 2,
child: Icon(Icons.ac_unit, size: 48, color: Colors.blue)
),
ElevatedButton(
child: Text("Button 2"),
onPressed:(){},
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(Size.square(70))
)
),
Spacer(flex: 1),
ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}),
]
)
3. 添加/删除子项
可以将一些子小部件添加到 Column 或从 Column 中删除其中一些。执行以下操作可能会导致意外结果(以下是错误的代码片段):
class SomeWidgetState extends State<SomeWidget> {
List<Widget> _children;
void initState() {
_children = [];
}
void someHandler() {
setState(() {
_children.add(newWidget);
});
}
Widget build(BuildContext context) {
// Reusing `List<Widget> _children` here is problematic.
return Column(children: this._children);
}
}
要解决上述问题,需要遵守以下规则:
- 子小部件需要明确分配一个 Key 值,这有助于 Flutter 在子小部件数量变化时识别旧的或新的子小部件。
- 如果某个子小部件发生变化,或者子小部件的数量发生变化,则需要为
Column.children
创建一个新的 List 对象。
以下是正确的片段代码示例:
class SomeWidgetState extends State<SomeWidget> {
List<Widget> _children;
void initState() {
this._children = [];
}
// Add or remove some children..
void someHandler() {
setState(() {
// The key here allows Flutter to reuse the underlying render
// objects even if the children list is recreated.
this._children.add(newWidget(key: ...));
});
}
Widget build(BuildContext context) {
// Always create a new list of children as a Widget is immutable.
var newChildren = List.from(this._children);
this._children = newChildren;
return Column(children: this._children);
}
}
完整的示例代码如下:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'yiibai.com',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MyHomePageState();
}
}
class MyHomePageState extends State<MyHomePage> {
List<Widget> _children = [];
int idx = 0;
@override
void initState() {
super.initState();
this._children = [
ElevatedButton(
key: Key(this.idx.toString()),
child: Text("Button " + idx.toString()),
onPressed: (){}
)
];
}
void addChildHandler() {
this.idx++;
this.setState(() {
var newChild = ElevatedButton(
key: Key(this.idx.toString()),
child: Text("Button " + idx.toString()),
onPressed: (){}
);
this._children.add(newChild);
});
}
@override
Widget build(BuildContext context) {
// Create new List object:
this._children = this._children == null? [] : List.from(this._children);
return Scaffold(
appBar: AppBar(
title: Text("Flutter Column Example")
),
body: Center(
child: Column (
children: this._children
)
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
this.addChildHandler();
}
),
);
}
}
运行效果如下所示:
4. mainAxisAlignment
mainAxisAlignment
属性用于指定子部件在主轴上的排列方式。对于 Column,主轴是主要的垂直轴。
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start
MainAxisAlignment.start
如果 verticalDirection = VerticalDirection.down
(默认) 和 mainAxisAlignment = MainAxisAlignment.start
,Column 的子部件将从上到下并排放置。
示例代码:MainAxisAlignment.start
Column (
mainAxisAlignment: MainAxisAlignment.start,
children: [
ElevatedButton(child: Text("Long Button 1"), onPressed:(){}),
ElevatedButton(
child: Text("Button 2"),
onPressed:(){},
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(Size.square(70))
)
),
ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){})
]
)
效果如下:
MainAxisAlignment.center
mainAxisAlignment: MainAxisAlignment.center
MainAxisAlignment.end
使用 verticalDirection = VerticalDirection.down
(默认)和 mainAxisAlignment = MainAxisAlignment.end
,Column 的子部件将从下到上并排放置。
mainAxisAlignment: MainAxisAlignment.end
MainAxisAlignment.spaceBetween
mainAxisAlignment: MainAxisAlignment.spaceBetween
MainAxisAlignment.spaceEvenly
mainAxisAlignment: MainAxisAlignment.spaceEvenly
MainAxisAlignment.spaceAround
mainAxisAlignment: MainAxisAlignment.spaceAround
5. mainAxisSize
mainAxisSize
属性指定 Column 应占用多少垂直空间。它的默认值是 MainAxisSize.max
意味着 Column 试图占据尽可能多的垂直空间。
如果有一个带有flex > 0 && fit != FlexFit.loose
的子widget,Column 无论mainAxisSize
的值如何,都会尝试占用尽可能多的空间。
相反,如果 mainAxisSize = MainAxisSize.min
,则 Column 将为其所有子小部件提供足够的高度。
MainAxisSize mainAxisSize: MainAxisSize.max
6. crossAxisAlignment
crossAxisAlignment
属性用于指定子小部件在交叉轴上的排列方式。至于Column,横轴就是横轴。
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center
CrossAxisAlignment.start
在 textDirection = TextDirection.ltr
(默认)和 crossAxisAlignment = CrossAxisAlignment.start
的情况下,Column 的子部件将放置在靠近其左边缘的位置。
CrossAxisAlignment.center
crossAxisAlignment: CrossAxisAlignment.center
rossAxisAlignment.end
在 textDirection = TextDirection.ltr
(默认)和 crossAxisAlignment = CrossAxisAlignment.end
的情况下,Column 的子小部件将放置在靠近 Column 的右边缘。
crossAxisAlignment: CrossAxisAlignment.end
CrossAxisAlignment.stretch
crossAxisAlignment: CrossAxisAlignment.stretch
CrossAxisAlignment.baseline
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic
7. textDirection
textDirection
属性指定 Column 的子小部件在水平轴上的排列方式以及“start”和“end”这两个词的解释方式。
TextDirection textDirection
// TextDirection enum:
TextDirection.ltr (Left to Right) (Default)
TextDirection.rtl (Right to Left)
如果 textDirection = TextDirection.ltr
(默认),单词“start”将对应于“left”,单词“end”将对应于“right”。
相反,在 textDirection = TextDirection.rtl
的情况下,单词“start”将对应于“right”,而单词“end”将对应于“left”。
8. verticalDirection
VerticalDirection
属性指定 Column 的子部件如何在主轴(垂直轴)上排列,以及如何解释“start”和“end”这两个词。
VerticalDirection verticalDirection: VerticalDirection.down
// VerticalDirection enum:
VerticalDirection.down (Default)
VerticalDirection.up
如果verticalDirection = VerticalDirection.down
(默认),单词“start”将对应于“top”,单词“end”将对应于“bottom”。
相反,如果verticalDirection = VerticalDirection.up
,则“start”一词将对应于“bottom”,而“end”一词将对应于“top”。
9. textBaseline
如果根据基线对齐子小部件,则 textBaseline
属性指定将使用哪种基线。
TextBaseline textBaseline: TextBaseline.alphabetic
// TextBaseline enum:
TextBaseline.alphabetic (Default)
TextBaseline.ideographic
示例代码:
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic