美文网首页
Flutter学习(七)布局Widget

Flutter学习(七)布局Widget

作者: yanhooIT | 来源:发表于2020-04-13 21:37 被阅读0次

Single-child layout widgets

  • Align对齐Widget
class AlignDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      // 添加容器背景颜色,便于更加直观的学习布局Widget
      color: Colors.yellow,
      // 对齐Widget
      child: Align(
        // 要布局的子Widget
        child: Icon(Icons.pets, size: 36, color: Colors.red),
        // 对其方式
        alignment: Alignment.center,
        // 宽度因子,不设置的情况,会尽可能大
        // 3表示Align的宽度是子组件宽度的3倍
        widthFactor: 3,
        // 高度因子,不设置的情况,会尽可能大
        // 3表示Align的高度是子组件高度的3倍
        heightFactor: 3,
      ),
    );
  }
}
  • Center表示居中对齐
class CenterDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      // 添加容器背景颜色,便于更加直观的学习布局Widget
      color: Colors.yellow,
      // 事实上Center组件继承自Align,只是将alignment设置为Alignment.center
      child: Center(
        // 要布局的子Widget
        child: Icon(Icons.pets, size: 36, color: Colors.red),
        // 宽度因子,不设置的情况,会尽可能大
        // 3表示Align的宽度是子组件宽度的3倍
        widthFactor: 3,
        // 高度因子,不设置的情况,会尽可能大
        // 3表示Align的高度是子组件高度的3倍
        heightFactor: 3,
      ),
    );
  }
}
  • Padding通常用于设置子Widget到父Widget的边距
class PaddingDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      // 添加容器背景颜色,便于更加直观的学习布局Widget
      color: Colors.yellow,
      // Padding通常用于设置子Widget到父Widget的边距
      child: Padding(
        child: Text(
          "莫听穿林打叶声,何妨吟啸且徐行。竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。",
          style: TextStyle(color: Colors.redAccent, fontSize: 18),
        ),
        padding: EdgeInsets.all(18),
      ),
    );
  }
}
  • Container是一个容器
/* 如果你需要一个视图,有背景颜色、图像、有固定的尺寸、需要一个边框、圆角等效果,那么就可以使用Container组件
    Container({
    this.alignment,                   // 对齐方式
    this.padding,                     // 容器内补白,属于decoration的装饰范围
    Color color,                      // 背景色
    Decoration decoration,            // 背景装饰
    Decoration foregroundDecoration,  // 前景装饰
    double width,                     // 容器的宽度
    double height,                    // 容器的高度
    BoxConstraints constraints,       // 容器大小的限制条件
    this.margin,                      // 容器外补白,不属于decoration的装饰范围
    this.transform,                   // 变换
    this.child,
    })
 */
class ContainerDemo1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        // color和decoration是互斥的,实际上,当指定color时,Container内会自动创建一个decoration
        color: Color.fromRGBO(3, 3, 255, .5),
        width: 100,
        height: 100,
        child: Icon(Icons.pets, size: 32, color: Colors.white),
      ),
    );
  }
}
  • Container有一个非常重要的属性decoration
/*
 const BoxDecoration({
    this.color,                       // 颜色,会和Container中的color属性冲突
    this.image,                       // 背景图片
    this.border,                      // 边框,对应类型是Border类型,里面每一个边框使用BorderSide
    this.borderRadius,                // 圆角半径设置
    this.boxShadow,                   // 阴影效果
    this.gradient,                    // 渐变效果
    this.backgroundBlendMode,         // 背景混合模式
    this.shape = BoxShape.rectangle,  // 形变
  })
*/
class ContainerDemo2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        // 和decoration属性中的color属性冲突
//        color: Color.fromRGBO(3, 3, 255, .5),
        width: 150,
        height: 150,
        child: Icon(Icons.pets, size: 32, color: Colors.white),
        decoration: BoxDecoration(
            color: Colors.amber,
            // 背景颜色
            border: Border.all(
                color: Colors.redAccent,
                width: 3,
                style: BorderStyle.solid
            ),
            // 这里也可以使用Border.all统一设置
//            top: BorderSide(
//              color: Colors.redAccent,
//              width: 3,
//              style: BorderStyle.solid
//            ),
            // 这里也可以使用.only分别设置
            borderRadius: BorderRadius.circular(20),
            // 阴影效果
            boxShadow: [
              BoxShadow(
                  offset: Offset(5, 5),
                  color: Colors.black54,
                  blurRadius: 5
              )
            ],
            // 会和borderRadius冲突
//          shape: BoxShape.circle,
            // 渐变效果:由绿渐变成红色
            gradient: LinearGradient(colors: [Colors.green, Colors.red])
        ),
      ),
    );
  }
}
  • 通过Container+BoxDecoration来实现圆角图像
// 通过 Container+BoxDecoration 来实现圆角图像
class ContainerDemo3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 200,
        height: 200,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(20),
            image: DecorationImage(
              image: NetworkImage("https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg"),
            )
        ),
      ),
    );
  }
}

Multi-child layout widgets

Flex、Row、Column
  • Row、Column组件是对Flex组件的封装,主要体现在属性direction
  • direction的值为Axis.horizontal的时候,则是Row,行排布
  • direction的值为Axis.vertical的时候,则是Column,列排布
  • 先了解Row、Column组件主轴(MainAxis)交叉轴(CrossAxis)的概念
    Row、Column组件的主轴(MainAxis)和交叉轴(CrossAxis)
  • Row
/// Row特点:
/// (1)水平方向尽可能占据比较大的空间
/// (2)水平方向也包裹内容, 那么设置mainAxisSize: MainAxisSize.min
/// (3)垂直方向包裹内容
class RowDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /**
     * Row({
     *    // 绑定GlobalKey,用于数据传递
          Key key,

          // 主轴对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义
          mainAxisAlignment,

          // 表示Row在主轴(水平)方向占用的空间
          mainAxisSize,

          // 交叉轴对齐方式
          crossAxisAlignment,
          // 表示纵轴的对齐方向
          verticalDirection,

          // 文本方向,默认为系统当前环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)
          textDirection,

          // 基线,只对文本有效
          // 只有crossAxisAlignment设置成了baseline,这个属性才生效
          textBaseline,

          // 子控件数组[]
          children,
        })
     */
    return Row(
      /** MainAxisAlignment:
       *  如果mainAxisSize值为MainAxisSize.min,则此属性无意义
       *  - start: 主轴的开始位置挨个摆放元素(默认值)
       *  - end: 主轴的结束位置挨个摆放元素
       *  - center: 主轴的中心点对齐
       *  - spaceBetween: 左右两边的间距为0, 其它元素之间平分间距
       *  - spaceAround: 左右两边的间距是其它元素之间的间距的一半
       *  - spaceEvenly: 所有的间距平分空间
       */
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      /** 表示Row在主轴(水平)方向占用的空间
       * 默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,即:无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度
       * MainAxisSize.min表示尽可能少的占用水平空间,当子widgets没有占满水平剩余空间,则Row的实际宽度等于所有子widgets占用的的水平空间
       */
      mainAxisSize: MainAxisSize.max,
      /** 纵轴的方向
       * - up: 起始位置从下往上
       * - down: 起始位置从上往下
       */
      verticalDirection: VerticalDirection.up,
      /** CrossAxisAlignment:
       *  - Row的高度等于子Widgets中最高的子元素高度
       *  - 参考系是verticalDirection
       *
       *  - start: 交叉轴的起始位置对齐
       *  - end: 交叉轴的结束位置对齐
       *  - center: 中心点对齐(默认值)
       *  - baseline: 基线对齐(必须有【文本】的时候才起效果)
       *  - stretch: 让Row占据交叉轴尽可能大的空间,将所有的子Widget交叉轴的高度, 拉伸到最大
       */
      crossAxisAlignment: CrossAxisAlignment.baseline,
      // 只有crossAxisAlignment设置成了baseline,这个属性才生效
      textBaseline: TextBaseline.ideographic,
      textDirection: TextDirection.ltr,
      children: <Widget>[
        // Expanded 来包裹 Container Widget,并且将它的宽度不设置值
        Expanded(
            /** flex属性
             * 弹性系数
             * Row会根据弹性系数来决定 子Widget 占据剩下空间的比例
             * 分配比例和宽度无关
             */
            flex: 1,
            child: Container(width: 0, height: 60, color: Colors.red, child: Text(
              "Hello",
              style: TextStyle(fontSize: 20),
            ))
        ),
        Expanded(
            flex: 2,// 绿色块宽度是红色块的两倍
            child: Container(width: 10000, height: 100, color: Colors.green,
              child: Text(
                "World",
                style: TextStyle(fontSize: 30),
              ))
        ),
        Container(width: 90, height: 80, color: Colors.blue,
          child: Text(
            "nba",
            style: TextStyle(fontSize: 12),
          )),
        Container(width: 50, height: 120, color: Colors.orange,
            child: Text(
              "cba",
              style: TextStyle(fontSize: 40),
            )),
      ],
    );
  }
}
  • TextBaseLine理解 TextBaseLine理解
  • Column,参数跟Row一样,这里就不一一说明了

/// Column特点:
/// (1)垂直方向尽可能占据比较大的空间
/// (2)垂直方向也包裹内容, 那么设置mainAxisSize: MainAxisSize.min
/// (3)水平方向包裹内容
class ColumnDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      mainAxisSize: MainAxisSize.max,
      verticalDirection: VerticalDirection.down,
      crossAxisAlignment: CrossAxisAlignment.start,
      textDirection: TextDirection.ltr,
      children: <Widget>[
        // Expanded 来包裹 Container Widget,并且将它的宽度不设置值
        Expanded(
          /** flex属性
           * 弹性系数
           * Column会根据弹性系数来决定 子Widget 占据剩下空间的比例
           * 分配比例和高度无关
           */
            flex: 1,
            child: Container(width: 30, height: 60000, color: Colors.red)
        ),
        Expanded(
            flex: 2,// 绿色块宽度是红色块的两倍
            child: Container(width: 100, height: 100, color: Colors.green)
        ),
        Container(width: 90, height: 80, color: Colors.blue),
        Container(width: 50, height: 120, color: Colors.orange),
      ],
    );
  }
}
Stack
  • 在开发中,我们多个组件很有可能需要重叠显示,比如在一张图片上显示文字或者一个按钮等,在Flutter中我们需要使用层叠布局Stack
  • 示例代码
/// 有状态改变
class _StackDemo2State extends State<StackDemo2> {
  bool _isFavor = false;

  @override
  Widget build(BuildContext context) {
    /**
     * Stack默认的大小是包裹内容的
     *  - alignment: 从什么位置开始排布所有的子Widget
     *  - fit: expand(很少使用) 将子元素拉伸到尽可能大
     *  - overflow: 超出部分【显示/隐藏】
     */
    return Stack(
      children: <Widget>[
        Image.asset("assets/images/xuebao.png"),
        Positioned(
          left: 0,
          right: 0,
          bottom: 0,
          child: Container(
            // 内边距
            padding: EdgeInsets.symmetric(horizontal: 8),
            color: Color.fromARGB(150, 0, 0, 0),
            child: Row(
              // 左右两边的间距为0, 其它元素之间平分间距
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Text(
                  "进击的巨人挺不错的",
                  style: TextStyle(fontSize: 20, color: Colors.white),
                ),
                IconButton(
                  icon: Icon(
                    Icons.favorite,
                    color: _isFavor? Colors.red : Colors.white,
                  ),
                  onPressed: () {
                    setState(() {
                      _isFavor = !_isFavor;
                    });
                  },
                )
              ],
            ),
          ),
        )
      ],
    );
  }
}

/// 无状态改变
class StackDemo1 extends StatelessWidget {
  const StackDemo1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /**
     * Stack默认的大小是包裹内容的
     *  - alignment: 从什么位置开始排布所有的子Widget
     *  - fit: expand(很少使用) 将子元素拉伸到尽可能大
     *  - overflow: 超出部分【显示/隐藏】
     */
    return Stack(
        alignment: AlignmentDirectional.bottomCenter,
//        fit: StackFit.expand,
//        overflow: Overflow.visible,
        children: <Widget>[
          Image.asset(
            "assets/images/xuebao.png",
//            width: 300,
            fit: BoxFit.fill,
          ),
          // Positioned: 设置子元素的绝对定位
          Positioned(
              // 距离父容器左边0像素
              left: 0,
              bottom: 0,
              right: 0,
              child: Container(
                width: 150,
                height: 50,
                color: Color.fromARGB(150, 0, 0, 0),
              )
          ),
          // Positioned: 设置子元素的绝对定位
          Positioned(
              // 距离父容器右边5像素
              right: 5,
              bottom: 5,
              child: Text(
                "进击的巨人",
                style: TextStyle(fontSize: 30, color: Colors.yellow),
              )
          )
        ]
    );
  }
}

相关文章

网友评论

      本文标题:Flutter学习(七)布局Widget

      本文链接:https://www.haomeiwen.com/subject/lyscmhtx.html