Flutter:页面布局摘要

说明:
以下说的类似都是以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
  )
)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值