说明:
以下说的类似都是以Android端为例。
一、设置Widget宽高:
1.使用ConstrainedBox+BoxConstraints设置Widget宽高:
BoxConstraints设置的几种方式:
BoxConstraints(minWidth: 最小宽度, maxWidth: 最大宽度, minHeight: 最小高度, maxHeight: 最大高度); //设置最小+最大宽高
BoxConstraints.tight(Size size); //设置固定宽高
BoxConstraints.expand(); //设置最大宽高
(1)设置Widget最小最大宽高:
ConstrainedBox(
constraints: BoxConstraints(minWidth: 最小宽度, maxWidth: 最大宽度, minHeight: 最小高度, maxHeight: 最大高度), //设置Widget最小最大宽高
child: ... //省略Widget
)
(2)设置Widget固定宽高:
ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 宽度, height: 高度), //设置Widget固定宽高
child: ... //省略Widget
)
2.使用SizedBox设置Widget宽高:
SizedBox(width: 80.0, height: 80.0, //设置Widget固定宽高
child: ... //省略Widget
)
3.使用UnconstrainedBox去除父布局大小限制:
ConstrainedBox(
constraints: BoxConstraints(minWidth: 父最小宽度, minHeight: 父最小高度), //父布局宽高设置
child: UnconstrainedBox( //去除父级限制
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 子最小宽度, minHeight: 子最小高度), //子Widget宽高设置
child: ... //省略子Widget
)
)
)
二、布局类Widget(含多个子Widget,类似ViewGroup):
1.线性布局Row与Column(类似LinearLayout水平与垂直模式):
(1)Row实现水平方向布局(类似LinearLayout.orientation=horizonal):
Row(
mainAxisSize: MainAxisSize.max, //水平方向宽度(高度需要借助ConstrainedBox+BoxConstraints或SizedBox),(默认)max最大,min为最小
textDirection: TextDirection.ltr, //水平方向布局顺序,(默认)ltr从左往右、rtl从右往左
mainAxisAlignment: MainAxisAlignment.start, //水平对齐方式,start左对齐、end右对齐、center水平居中、spaceEvenly将剩余空间均分成多份穿插在各child之间,textDirection=rtl时左右对齐反过来
verticalDirection: VerticalDirection.down, //垂直方向布局顺序,,(默认)down从上到下、up从下到上
crossAxisAlignment: CrossAxisAlignment.center,//垂直对齐方式,start顶部对齐、end底部对齐、center垂直居中,verticalDirection=up时上下对齐反过来
children: <Widget>[...] //省略子Widget列表
)
(2)Column实现垂直方向布局(类似LinearLayout.orientation=vertical):
Column( //配置与Row完全一致
mainAxisSize: MainAxisSize.max, //垂直方向高度(宽度需要借助ConstrainedBox+BoxConstraints或SizedBox),(默认)max最大,min为最小
...
children: <Widget>[...] //省略子Widget列表
)
2.弹性布局Flex+Expanded(与线性布局一致):
(1)Flex+Expanded实现水平或垂直方向布局:
Flex(
direction: Axis.horizontal, //子Widget排列方向, horizontal水平方向,vertical垂直方向
children: <Widget>[ //子Widget列表,以下2个子Widget各占一半
Expanded(
flex: 1, //弹性系数,类似LinearLayout.weight
child: 任意Widget(
... //省略Widget具体内容
)
),
Expanded(
flex: 1, //弹性系数,类似LinearLayout.weight
child: 任意Widget(
... //省略Widget具体内容
)
)
]
)
(2)Spacer实现空布局(Flex包装类,只占空间,无子Widget):
Spacer(
flex: 1, //弹性系数,类似LinearLayout.weight
)
3.流式布局Wrap:
(1)Wrap实现流式布局(子Widget排不下会换行,水平排列时有点像GridView显示效果):
Wrap(
direction = Axis.horizontal, //子Widget排列方式, horizontal水平方向,vertical垂直方向
alignment = WrapAlignment.start, //水平方向对齐方式,start左对齐,end右对齐,center水平居中
spacing: 数值, //水平方向子widget间距
runAlignment: WrapAlignment.start, //垂直方向对齐方式,start顶部对齐,end底部对齐,center垂直居中
runSpacing: 数值, //垂直方向子widget间距
... //省略其他与Row/Column共有属性
children: <Widget>[...] //省略子Widget列表
)
(2)Flow实现自定义布局(类似自定义ViewGroup):
Flow(
delegate: 自定义Delegate(...), //在自定义Delegate中处理子Widget排列方式
children: <Widget>[...] //省略子Widget列表
)
class 自定义Delegate extends FlowDelegate {
TestFlowDelegate({...}); //省略参数
@override
void paintChildren(FlowPaintingContext context) { //重写paintChildren方法,排列每个子widget位置
for (int i = 0; i < context.childCount; i++) {
//1.获取每个子Widget的宽高
var itemWidth = context.getChildSize(i)!.width; //获取每个子Widget的宽度
var itemHeight = context.getChildSize(i)!.height; //获取每个子Widget的高度
//2.算出每个子Widget的x轴坐标与y轴坐标
...
//3.绘制子widget
context.paintChild(i, transform: Matrix4.translationValues(x轴坐标, y轴坐标, 0.0));
}
}
@override
Size getSize(BoxConstraints constraints) { //重写getSize,返回Flow宽高
for (int i = 0; i < context.childCount; i++) {
context.getChildSize(i)!.width; //获取每个子Widget的宽度
context.getChildSize(i)!.height; //获取每个子Widget的高度
... //计算总宽与总高
}
return Flow宽高;
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return oldDelegate != this;
}
}
4.Stack+Positioned实现层叠布局(类似FrameLayout):
Stack(
alignment: Alignment.center, //未设位置或只设部分位置widget的对齐方式
fit: StackFit.loose, //未设位置的子Widget填充方式,loose为子Widget自身宽高、expand为拉伸到Stack宽高
clipBehavior: Clip.hardEdge, //超出Stack宽高部分如何剪裁,hardEdge为裁剪超出部分
children: <Widget>[ //由每个Positioned设置各子widget位置
Positioned(
left: 数值, //离左边距离
top: 数值, //离顶部距离
right: 数值, //离右边距离
bottom: 数值, //离底部边距离
width: 数值, //宽度
height: 数值, //高度
child: ...//省略具体Widget
),
Positioned(
... //同上
child: ... //省略具体Widget
),
... //可使用非Positioned的Widget
] //省略子Widget列表
)
5.对齐与相对定位布局:
(1)Alignment位置工具类:
Alignment以矩形中心点作为坐标原点,即Alignment(0.0, 0.0) //第1参数为x轴偏移量,第2参数为y轴偏移量。//x从-1到1代表从矩形左边到右边的距离,y从-1到1代表从矩形顶部到底边的距离
Alignment相对矩形位置(x轴或y轴偏移量>1或<-1时将超出矩形):
矩形左上角顶点:Alignment.topLeft或Alignment(-1.0, -1.0)
矩形右上角顶点:Alignment.topRight或Alignment(1.0, -1.0)
矩形左下角顶点:Alignment.bottomLeft或Alignment(-1.0, 1.0)
矩形右下角顶点:Alignment.bottomRight或Alignment(1.0, 1.0)
矩形中心点:Alignment.center或Alignment(0.0, 0.0)
矩形右侧垂直方向中心点:Alignment.centerRight或Alignment(1.0, 0.0)
矩形左侧垂直方向中心点:Alignment.centerLeft或Alignment(-1.0, 0.0)
矩形顶部水平方向中心点:Alignment.topCenter或Alignment(0.0, -1.0);
矩形底部水平方向中心点:Alignment.bottomCenter或Alignment(0.0, 1.0)
(2)FractionalOffset位置工具类:
FractionalOffset以矩形左上角顶点作为坐标原点,即FractionalOffset(0.0, 0.0) //第1参数为x轴偏移量,第2参数为y轴偏移量。//x从0到1代表从矩形左边到右边的距离,y从0到1代表从矩形顶部到底边的距离
FractionalOffset相对矩形位置(x轴或y轴偏移量>1或<-1时将超出矩形):
矩形左上角顶点:FractionalOffset.topLeft或FractionalOffset(0.0, 0.0);
矩形右上角顶点:FractionalOffset.topRight或FractionalOffset(1.0, 0.0);
矩形左下角顶点:FractionalOffset.bottomLeft或FractionalOffset(0.0, 1.0);
矩形右下角顶点:FractionalOffset.bottomRight或FractionalOffset(1.0, 1.0);
矩形中心点:FractionalOffset.center或FractionalOffset(0.5, 0.5);
矩形右侧垂直方向中心点:FractionalOffset.centerRight或FractionalOffset(1.0, 0.5);
矩形左侧垂直方向中心点:FractionalOffset.centerLeft或FractionalOffset(0.0, 0.5);
矩形顶部水平方向中心点:FractionalOffset.topCenter或FractionalOffset(0.5, 0.0);
矩形底部水平方向中心点:FractionalOffset.bottomCenter或FractionalOffset(0.5, 1.0);
(3)Align+Alignment(FractionalOffset)实现相对定位布局:
Align(
widthFactor: 倍数, //子Widget宽度 = 倍数 x 子Widget宽度
heightFactor: 倍数, //子Widget高度 = 倍数 x 子Widget高度
alignment: Alignment.center, //子Widge以父Widget的中心点作为起始位置
//alignment: FractionalOffset.center, //子Widge以父Widget的中心点作为起始位置
child: ... //只能有一个子Widget
)
(4)Center实现居中定位布局:
Center(//实际就是设置了Alignment.center的Align
widthFactor: 倍数, //子Widget宽度 = 倍数 x 子Widget宽度
heightFactor: 倍数, //子Widget高度 = 倍数 x 子Widget高度
child: ... //只能有一个子Widget
)
6.其他辅助类布局:
(1)LayoutBuilder:
说明:类似包装类Widget,将原Widget包装,可实现例如打印日志、根据设备尺寸动态调整布局等功能。
class 自定义Widget extends StatelessWidget {
const 自定义Widget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder( //在LayoutBuilder拿到父组件传递的宽高,处理子Widget
builder: (BuildContext context, BoxConstraints constraints) {
... //在此处可对原Widget进行处理
return 原Widget;
},
);
}
}
三、辅助类(容器类)Widget(只含1个子Widget):
说明:对子Widget添加装饰,如添加背景、平移/旋转/缩放、剪裁等
EdgeInsets用法:
EdgeInsets.fromLTRB(左边距值, 上边距值, 右边距值, 下边距值):指定四个方向的边距
EdgeInsets.all(四个方向边距值) : 四个方向均使用相同的边距
EdgeInsets.only(left: 左边距值, top: 上边距值, right: 右边距值, bottom: 下边距值):设置某个方向的边距(也可以同时设置多个方向的边距)。
EdgeInsets.symmetric(vertical: 垂直边距值, horizontal: 水平边距值):垂直边距为top和bottom,水平边距为left和right
1.SingleChildScrollView实现子Widget超宽高时水平/垂直滚动(类似ScrollView):
Scrollbar( //用于显示进度条,可以没有
child: SingleChildScrollView(
scrollDirection: Axis.vertical, //滚动方向,(默认)vertical垂直方向、horizontal水平方向
primary: true, //是否使用系统默认PrimaryScrollController,默认为true
controller: 自定义ScrollController, //监听滚动事件
child: ... //省略子Widget,子Widget超宽高时水平或垂直滚动
)
)
2.Padding实现Widget内边距(类似android:padding):
Padding(
padding: EdgeInsets.only(left: 10, top: 10), //为下面的Widget设置内边距
child: ..., //省略单个Widget
)
3.DecoratedBox+BoxDecoration实现Widget背景(纯色/渐变)+阴影:
DecoratedBox(
decoration: BoxDecoration(
color: 背景色, //设置背景颜色
gradient: LinearGradient(colors:[颜色值1, 颜色值2]), //设置背景色线性渐变
// gradient: RadialGradient(colors:[颜色值1, 颜色值2],center: Alignment.topLeft, radius: 半径), //设置背景色径向渐变
borderRadius: BorderRadius.circular(圆角半径), //设置背景圆角
boxShadow: [ //阴影,可设多个
BoxShadow(
color: 阴影颜色,
offset: Offset(x轴偏移值, y轴偏移值), //阴影宽度
blurRadius: 圆角半径 //设置阴影圆角
)
]
),
position: DecorationPosition.background, //background绘制Widget背景、foreground绘制Widget前景
child: ..., //省略当前Widget
)
4.Transform实现Widget平移/旋转/缩放:
(1)平移:
Transform.translate(
offset: Offset(x轴移动距离, y轴移动距离), //将Widget平移指定距离
child: ..., //省略当前Widget
)
(2)旋转:
Transform.rotate(
angle: 角度, //将Widget旋转指定角度
child: ..., //省略当前Widget
)
(3)缩放:
Transform.scale(
scale: 倍数, //将Widget缩放指定倍数,>1放大、<1缩小
child: ..., //省略当前Widget
)
(4)矩阵变换:
Transform(
alignment: Alignment.topLeft, //左上角为原点
transform: Matrix4.skewY(Y轴倾斜弧度), //沿Y轴倾斜指定弧度
//transform: Matrix4.rotationZ(Z轴旋转弧度), //沿Z轴旋转指定弧度
child: ..., //省略当前Widget
)
5.RotatedBox实现Widget平移/旋转/缩放:
(1)平移:
待补充
(2)旋转:
RotatedBox(
quarterTurns: 2, //旋转四分之二圈(180度)
child: ..., //省略当前Widget
)
(3)缩放:
待补充
6.Container实现Widget内外边距+背景+平移/旋转/缩放:
说明:它是DecoratedBox、ConstrainedBox、Transform、Padding、Align等Widget组合的多功能Widget
Container(
alignment: Alignment.center, //居中对齐
padding: EdgeInsets.only(left: 左边距值, top: 上边距值, right: 右边距值, bottom: 下边距值), //设置内边距值,类似android:padding
margin: EdgeInsets.only(left: 左边距值, top: 上边距值, right: 右边距值, bottom: 下边距值), //设置外边距值,类似android:margin
//width: 宽度值, //设置宽度值
//height: 高度值, //设置高度值
constraints: BoxConstraints.tightFor(width: 宽度, height: 高度), //设置宽高限制
//color: ..., //设置纯背景色
decoration: BoxDecoration( //设置复杂背景,同本章2.DecoratedBox+BoxDecoration小节配置
... //省略BoxDecoration配置
),
transform: Matrix4.skewY(Y轴倾斜弧度), //同本章3.Transform小节配置
child: ..., //省略子Widget
)
7.Widget裁剪:
(1)裁剪为圆形:
ClipOval(
child: ..., //省略当前Widget
)
(2)剪裁为圆角矩形:
ClipRRect(
borderRadius: BorderRadius.circular(圆角半径), //设置矩形四角圆角半径
child: ..., //省略当前Widget
)
(3)裁剪溢出部分:
ClipRect(//裁剪溢出部分
child: ..., //省略当前Widget
)
(4)CustomClipper实现自定义剪裁:
<1>自定义剪裁类:
class 自定义剪裁类名 extends CustomClipper<Rect> {
@override
Rect getClip(Size size) => Rect.fromLTWH(left, top, width, height); //设置剪裁区域
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) => false; //(性能好)剪裁区域固定时返回false,剪裁区域动态变化时返回true
}
<2>使用自定义剪裁:
ClipRect(//裁剪溢出部分
clipper: 自定义剪裁类名(), //使用自定义剪裁类
child: ..., //省略当前Widget
)
8.FittedBox空间适配:
Container(
... //省略其他参数
child: FittedBox(
fit: BoxFit.contain, //适配方式,BoxFit.contain按照比例缩放子Widget、BoxFit.none不缩放
alignment: Alignment.center, //对齐方式
clipBehavior: Clip.none, //是否剪裁,此处为不
child: ..., //省略子Widget
)
)