线性布局 Column Row
Row
Row 布局组件类似于 Android 中的 LinearLayout 线性布局,它用来做水平横向布局使用,里面的 children 子元素按照水平方向进行排列。
Row({
Key key,
// * 子元素集合
List<Widget> children = const <Widget>[],
// 主轴方向上的对齐方式(Row的主轴是横向轴)
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
// 在主轴方向(Row的主轴是横向轴)占有空间的值,默认是max
MainAxisSize mainAxisSize = MainAxisSize.max,
// 在交叉轴方向(Row是纵向轴)的对齐方式,Row的高度等于子元素中最高的子元素高度
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
// 水平方向子元素的排列方向:从左到右排列还是反向
TextDirection textDirection,
// 表示纵轴(垂直)的对齐排列方向,默认是VerticalDirection.down,表示从上到下。这个参数一般用于Column组件里
VerticalDirection verticalDirection = VerticalDirection.down,
// 字符对齐基线方式
TextBaseline textBaseline,
})
- MainAxisAlignment 主轴属性:主轴方向上的对齐方式,Row 是横向轴为主轴
enum MainAxisAlignment {
// 按照主轴起点对齐,例如:按照靠近最左侧子元素对齐
start,
// 将子元素放置在主轴的末尾,按照末尾对齐
end,
// 子元素放置在主轴中心对齐
center,
// 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,首尾子元素都靠近首尾,没有间隙。有点类似于两端对齐
spaceBetween,
// 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,但是首尾子元素的空白区域为1/2
spaceAround,
// 将主轴方向上的空白区域均分,使得子元素之间的空白区域相等,包括首尾子元素
spaceEvenly,
}
- CrossAxisAlignment 交叉属性:在交叉轴方向的对齐方式,Row 是纵向轴。Row 的高度等于子元素中最高的子元素高度。
enum CrossAxisAlignment {
// 子元素在交叉轴上起点处展示
start,
// 子元素在交叉轴上末尾处展示
end,
// 子元素在交叉轴上居中展示
center,
// 让子元素填满交叉轴方向
stretch,
// 在交叉轴方向,使得子元素按照baseline对齐
baseline,
}
- MainAxisSize 在主轴方向子元素占有空间的方式,Row 的主轴是横向轴。默认是 max
enum MainAxisSize {
// 根据传入的布局约束条件,最大化主轴方向占用可用空间,也就是尽可能充满可用宽度
max,
// 与max相反,是最小化占用主轴方向的可用空间
min,
}
Column
Column 是纵向排列子元素,属性和Row基本一致,只是方向有点不同而已。
Box Model 盒子模型
不同部分的说明:
- Margin(外边距) - 边框意外的距离。
- Border(边框) - 围绕在内边距和内容外的边框。
- Padding(内边距) - 边框内部到内容的距离。
- Content(内容) - 盒子的内容,显示文本和图像。
Container
Container 是一个组合类容器,它本身不对应具体的 RenderObject,它是 DecoratedBox、ConstrainedBox、Transform、Padding、Align 等组件组合的一个多功能容器,所以我们只需通过一个 Container 组件可以实现同时需要装饰、变换、限制的场景。
Container({
Key key,
// 容器子Widget对齐方式
this.alignment,
// 容器内部padding
this.padding,
// 背景色
Color color,
// 背景装饰
Decoration decoration,
// 前景装饰
this.foregroundDecoration,
// 容器的宽度
double width,
// 容器的高度
double height,
// 容器大小的限制条件
BoxConstraints constraints,
// 容器外部margin
this.margin,
// 变换,如旋转
this.transform,
// 容器内子Widget
this.child,
})
BoxDecoration 装饰
const BoxDecoration({
// 背景色
this.color,
// 背景图片
this.image,
// 边框样式
this.border,
// 边框圆角
this.borderRadius,
// 阴影
this.boxShadow,
// 渐变
this.gradient,
// 背景混合模式
this.backgroundBlendMode,
// 形状
this.shape = BoxShape.rectangle,
})
弹性布局Flex
弹性布局允许子组件按照一定比例来分配父容器空间。
我们可以发现 Column Row 组件都是继承与 Flex,功能非常强大,通常我们直接用 Column Row 即可。
Expanded
Expanded 只能放在 Flex、Column、Row 中使用
- 把包裹的元素撑开
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
Expanded(
child: Container(
color: Colors.amber,
),
),
const FlutterLogo(
size: 32,
),
],
),
);
}
- Flex 属性调整比例
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.amber,
),
),
const Expanded(
flex: 2,
child: FlutterLogo(
size: 32,
),
),
],
Spacer
留白撑开,很适合用在标题按钮的场景中
children: [
Container(
width: 50,
color: Colors.amber,
),
const Spacer(),
const FlutterLogo(
size: 32,
),
],
层叠布局Stack
Stack 允许子组件堆叠
Stack({
Key key,
// 对齐方式,默认是左上角(topStart)
this.alignment = AlignmentDirectional.topStart,
// 对齐方向
this.textDirection,
// 定义如何设置无定位子元素尺寸,默认为loose
this.fit = StackFit.loose,
// 对超出 Stack 显示空间的部分如何剪裁
this.clipBehavior = Clip.hardEdge,
// 子元素
List<Widget> children = const <Widget>[],
})
Positioned
根据 Stack 的四个角来确定子组件的位置
const Positioned({
Key key,
this.left, // 上下左右位置
this.top,
this.right,
this.bottom,
this.width, // 宽高
this.height,
@required Widget child,
})
流式布局 Wrap
用 Row 的时候可以发现子元素不会自动换行,这时候就需要 Wrap 了。
Wrap({
this.direction = Axis.horizontal,
// 主轴方向的对齐方式
this.alignment = WrapAlignment.start,
// 主轴方向子widget的间距
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>[],
})
对齐定位 Align
调整子元素在父元素的位置
Align({
Key key,
// 需要一个AlignmentGeometry类型的值
// AlignmentGeometry 是一个抽象类,
// 它有两个常用的子类:Alignment和 FractionalOffset
this.alignment = Alignment.center,
// 两个缩放因子
// 会分别乘以子元素的宽、高,最终的结果就是 Align 组件的宽高
this.widthFactor,
this.heightFactor,
Widget child,
})
Alignment
Alignment 是从 Align 的中心点出发
/// 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);
Alignment(-1.0, -1.0) 标识从中心点出发,左上角
FractionalOffset
这种方式是固定从左上角出发
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Align(
alignment: FractionalOffset(0.5, 0.1),
child: FlutterLogo(
size: 50,
),
),
);
}
用 FractionalOffset 对象,输入 0~1 的比例值
Center
Center 是集成了 Align 对象,默认 alignment=Alignment.center
Center 定义, 少了一个 alignment 参数
class Center extends Align {
/// Creates a widget that centers its child.
const Center({ Key? key, double? widthFactor, double? heightFactor, Widget? child })
: super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}
然后 Align 定义, 默认了 this.alignment = Alignment.center
class Align extends SingleChildRenderObjectWidget {
/// Creates an alignment widget.
///
/// The alignment defaults to [Alignment.center].
const Align({
Key? key,
this.alignment = Alignment.center,
this.widthFactor,
this.heightFactor,
Widget? child,
}) : assert(alignment != null),
assert(widthFactor == null || widthFactor >= 0.0),
assert(heightFactor == null || heightFactor >= 0.0),
super(key: key, child: child);
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。