Day07 - Flutter 小部件的布局

简介: Day07 - Flutter 小部件的布局

概述


  • 单子布局组件
  • 多子布局组件


一、单子布局组件



单子布局组件的含义是其只有一个子组件,可以通过设置一些属性设置该子组件所在的位置信息等。

比较常用的单子布局组件有:AlignCenterPaddingContainer

  • 1.1、对齐组件
  • 1.1.1、对齐介绍
    看到Align这个词,我们就知道它有我们的 对齐方式 有关。
    在其他端的开发中(iOS,Android,前端)Align通常只是一个属性而已,但是Flutter中Align也是一个组件。
    我们可以通过二进制来看一下Align有一些属性:


const Align({
   Key key,
   this.alignment: Alignment.center, // 对齐方式,默认居中对齐
   this.widthFactor, // 宽度因子,不设置的情况,会尽可能大
   this.heightFactor, // 高度因子,不设置的情况,会尽可能大
   Widget child // 要布局的子Widget
})

提示:这里我们特别解释一下 widthFactorheightFactor 作用:

  • 因为子组件在父组件中的对齐方式必须有一个合并,就是父组件得知道自己的范围(宽度和高度);
  • 如果widthFactor和heightFactor不设置,那么替换Align会重置的大(替换为自己所在的父组件);
  • 我们也可以对他们进行设置,尺寸widthFactor设置为2,那么相对于Align的宽度是子组件跨度的2倍;也就是是子组件的 几倍


  • 1.1.2、对齐代码


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Align(
        child: Icon(Icons.pets, size: 36, color: Colors.red),
        alignment: Alignment.bottomRight,
        widthFactor: 2,
        heightFactor: 2,
     );
   }
}


  • 1.2、中心组件
  • 1.2.1、中心介绍
    实际上 Center组件继承自Align,只是将alignment设置为Alignment.center
    原始码分析:


class Center extends Align {
   const Center({
      Key key,
      double widthFactor,
      double heightFactor,
      Widget child
   }) : super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}
  • 1.2.2、代码展示


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
       return Center(
           child: Icon(Icons.pets, size: 36, color: Colors.red),
       );
   }
}


  • 1.3、填充组件
  • 1.3.1、填充介绍
    Padding组件在其他端也是一个属性而已,但是在Flutter中是一个小部件,但是Flutter中没有Margin这样一个小部件,这是因为外边距也可以通过Padding来完成。
    填充通常用于设置子窗口小部件到父窗口小部件的边距(您可以称为是父组件的内边距或子窗口小部件的外边距)。
    原始码分析:


const Padding({
   Key key,
   @requiredthis.padding, // EdgeInsetsGeometry类型(抽象类),使用EdgeInsets
   Widget child,
})
  • 1.3.2、代码展示


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return Padding(
         padding: EdgeInsets.all(16),
         child: Text(
             "莫听穿林打叶声,何妨吟啸且徐行。竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。",
             style: TextStyle(
             color: Colors.redAccent,
             fontSize: 18
         ),
       ),
    );
  }
}


image.png


  • 1.4、集装箱组件Container组件其他其他Android中的View,iOS中的UIView。如果你需要一个视图,有一个背景颜色,图像,有固定的尺寸,需要一个边框,圆角等效果,那么就可以使用Container组件。
  • 1.4.1、容器介绍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,
})
  • 大多数属性在介绍其他容器时都已经介绍过了,不再重复述,但有两点需要说明:
  • 容器的大小可以通过width,height属性来指定,也可以通过constraints来指定。实际容器内部会根据width,height来生成一个constraints;
  • color和decoration是互斥的,实际上,当指定color时,容器内会自动创建一个装饰;


  • 1.4.2、集装箱代码


class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
      return Center(
         child: Container(
            color: Color.fromRGBO(3, 3, 255, .5),
            width: 100,
            height: 100,
            child: Icon(Icons.pets, size: 32, color: Colors.white),
         ),
      );
  }
}
  • 1.4.3、Box装潢
    Container有一个非常重要的属性decoration:
    他对应的类型是装修类型,但是它是一个抽象类。
    在开发中,我们经常使用它的实现类 BoxDecoration 来进行实例化。
    BoxDecoration常见属性:


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 MyHomeBody extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return Center(
          child: Container(
             // 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
                  //  ),
               borderRadius: BorderRadius.circular(20), // 这里也可以使用.only分别设置
               boxShadow: [
                    BoxShadow(
                       offset: Offset(5, 5),
                       color: Colors.purple,
                       // 模糊度
                       blurRadius: 5
                    )
               ],
              //  shape: BoxShape.circle, // 会和borderRadius冲突
              gradient: LinearGradient(
                colors: [
                    Colors.green,
                    Colors.red
                ]
             )
          ),
       ),
    );
  }
}
  • 1.4.4、通过Container+BoxDecoration来实现圆角图像


class HomeContent 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"),
                 )
             ),
          ),
      );
   }
}


二、多子布局组件



在开发中,我们经常需要将多个Widget放在一起进行布局,某些水平方向,垂直方向隔开,甚至有时候需要他们进行分解,其中图片上面放一段文字等;

这个时候我们需要使用多子布局部件(多子布局部件)。

比较常用的多子布局组件是(Row)行,(Column)列,(Stack)堆栈,我们来学习一下他们的使用。


  • 2.1、Flex 组件(很少直接使用)实际上,我们即将学习的Row组件和Column组件都继承自Flex组件。
  • Flex组件和行,列属性主要的区别就是多一个direction方向。
  • 当direction的增量Axis.horizontal的时候,则是Row。
  • 当direction的增量Axis.vertical的时候,则是Column。
  • 在学习 RowColumn 之前,我们先学习主轴和交叉轴的概念。
    因为行是一行排布,列是一列排布,那么这些都存在两个方向,并且两个小部件分布的方向应该是对立的。
    它们彼此都有 主轴(MainAxis)和 交叉轴(CrossAxis)的概念:
  • 对于行(Row)来说,主轴:横着(MainAxis)和交叉轴:竖着(CrossAxis)
  • 对于列(Column) 而言,主轴:竖着(主轴)和交叉轴:横着(CrossAxis)分别是下图
  • 2.2、Row行 组件
  • 1>、行介绍Row组件用于将所有的子控件排成一行,实际上这种布局应该是放置于Web的Flex布局。如果熟悉Flex布局,会发现非常简单。从源码中查看Row的属性:


Row({
   Key key,
   // 主轴对齐方式
   MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
   // 水平方向尽可能大
   MainAxisSize mainAxisSize = MainAxisSize.max, 
   // 交叉处对齐方式
   CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, 
   // 水平方向子widget的布局顺序(默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左))
   TextDirection textDirection, 
   // 表示Row纵轴(垂直)的对齐方向
   VerticalDirection verticalDirection = VerticalDirection.down, 
   // 如果上面是baseline对齐方式,那么选择什么模式(有两种可选)
   TextBaseline textBaseline, 
   List<Widget> children = const <Widget>[],
})


  • 部分属性详细解析
  • 主轴尺寸:
  • 表示行在主轴(水平)方向占用的空间,MainAxisSize.max 最小是,表示重置多的占用水平方向的空间,此时无论子小物件实际占用多少水平空间,行的宽度始终等于水平方向的最大宽度
  • MainAxisSize.min 表示缩减少的占用水平空间,当子小部件没有占满水平剩余空间,则行的实际宽度等于所有子小部件所占用的水平空间;
    mainAxisAlignment:表示子小部件在行所占用的水平空间内对齐方式
  • mainAxisAlignment:表示子小部件在行所占用的水平空间内对齐方式
  • 如果mainAxisSize变量MainAxisSize.min,则此属性无意义,因为子小部件的宽度等于行的宽度
  • 只有当mainAxisSize的增量MainAxisSize.max时,此属性才赋值
  • MainAxisAlignment.start表示沿textDirection的初始方向对齐,
  • 如textDirection为取值TextDirection.ltr时,则MainAxisAlignment.start表示左对齐,textDirection为取值TextDirection.rtl时表示从右对齐。
  • 而MainAxisAlignment.end和MainAxisAlignment.start正好相反;
  • MainAxisAlignment.center表示居中对齐。


提示:mainAxisAlignment

  • start: 主轴的开始位置挨个摆放元素
  • end: 主轴结束位置挨个摆放元素
  • center: 主轴的中心点对齐
  • spaceBetween: 左右两边的距离为 0,其他元素之间平分间距
  • spaceAround: 左右两边的距离是其他元素之间的距离的一半
  • spaceEvenly: 所有的间距平分空间


  • crossAxisAlignment:表示子控件在纵轴方向的对齐方式
  • Row的高度等于子Widgets中最高的子元素高度
  • 它的取值和MainAxisAlignment一样(包含start,end,center三个值)
  • 不同的是crossAxisAlignment的参考系是verticalDirection,即verticalDirection转换VerticalDirection.downcrossAxisAlignment.start指顶部对齐,verticalDirection转换VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.endcrossAxisAlignment.start正好相反;


提示:crossAxisAlignment

  • start: 交叉轴的起始位置对齐
  • end: 交叉轴的结束为止对齐
  • center: 中心点对齐(没默认值)
  • stretch: 基线对齐(必须有文本的时候才起效果)
  • baseline: 先Row占据交叉轴尽可能大的空间,将左所有的子Widget交叉轴的高度,拉伸到最大


  • 2>、示例代码


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return Row(
         mainAxisAlignment: MainAxisAlignment.spaceEvenly,
         crossAxisAlignment: CrossAxisAlignment.end,
         mainAxisSize: MainAxisSize.max,
         children: <Widget>[
            Container(color: Colors.red, width: 60, height: 60),
            Container(color: Colors.blue, width: 80, height: 80),
            Container(color: Colors.green, width: 70, height: 70),
            Container(color: Colors.orange, width: 100, height: 100),
         ],
      );
   }
}


  • 3>、mainAxisSize
    默认情况下,行会重新覆盖多的宽度,让子小部件在其中进行排布,这是因为mainAxisSize属性替换值是MainAxisSize.max。
    我们来看一下,如果这个值被修改为MainAxisSize.max会什么变化:



image.png


4>、Expanded 展开式


如果我们希望红色和黄色的容器Widget不要设置固定的宽度,而是替换剩余的部分,这个时候应该如何处理呢?

这个时候我们可以使用Expanded来包装Container Widget,并且将其的宽度不设置值,我们可以看到下图多余的空间被红色和黄色的部分分了

  • flex属性,弹性系数,Row会根据两个展开的弹性系数来决定它们剩下多少空间的比例

image.png


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return Row(
         mainAxisAlignment: MainAxisAlignment.spaceEvenly,
         crossAxisAlignment: CrossAxisAlignment.end,
         mainAxisSize: MainAxisSize.min,
         children: <Widget>[
            Expanded(
                flex: 1,
                child: Container(color: Colors.red, height: 60),
            ),
            Container(color: Colors.blue, width: 80, height: 80),
            Container(color: Colors.green, width: 70, height: 70),
            Expanded(
                flex: 1,
                child: Container(color: Colors.orange, height: 100),
            )
         ],
     );
   }
}
  • 2.3、Column 列组件列组件用于将所有的子控件排成一列,学会了前面的行后,列只是和行的方向不同而已。
  • 2.3.1>、专栏介绍,我们直接看它的源码:我们发现和Row属性是一致的


Column({
   Key key,
   MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
   MainAxisSize mainAxisSize = MainAxisSize.max,
   CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
   TextDirection textDirection,
   VerticalDirection verticalDirection = VerticalDirection.down,
   TextBaseline textBaseline,
   List<Widget> children = const <Widget>[],
})
  • 2.3.2>、专栏演练


class MyHomeBody extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
       return Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          crossAxisAlignment: CrossAxisAlignment.end,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
              Expanded(
                  flex: 1,
                  child: Container(color: Colors.red, width: 60),
              ),
              Container(color: Colors.blue, width: 80, height: 80),
              Container(color: Colors.green, width: 70, height: 70),
              Expanded(
                  flex: 1,
                  child: Container(color: Colors.orange, width: 100),
              )
          ],
       );
   }
}
  • 2.4、堆栈组件在开发中,我们多个组件很有可能需要重叠显示,某些在一张图片上显示文字或一个按钮等。在Android中可以使用Frame实现,在Web端可以使用绝对定位,在Flutter中我们需要使用布局Stack。
  • 2.4.1>、堆栈介绍Stack有一些属性:


Stack({
   Key key,
   this.alignment = AlignmentDirectional.topStart,
   this.textDirection,
   this.fit = StackFit.loose,
   this.overflow = Overflow.clip,
   List<Widget> children = const <Widget>[],
})
  • 参数解析:
  • 对齐:此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子小部件。所谓部分定位,在这里特指没有在某某轴上定位:左,右为横轴,顶部,bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
  • textDirection:和Row,Wrap的textDirection功能相同,都用于决定对齐对齐的参考系即:textDirection的变量TextDirection.ltr,则alignment的start代表左,end代表右; textDirection的大小TextDirection.rtl,则alignment的start代表右,end代表左。
  • fit:此参数用于决定没有定位的子小部件如何去适应Stack的大小。StackFit.loose表示使用子小部件的大小,StackFit.expand表示扩展伸到Stack的大小。
  • 溢出overflow:此属性决定如何显示超过堆栈显示空间的子部件,变化Overflow.clip时,超出部分会被剪裁(隐藏),转化Overflow.visible时则不会。


  • 2.4.2>、Stack  的 demo
    Stack会经常和Positioned一起来使用,Positioned可以决定组件在Stack中的位置,实现实现Web中的绝对定位效果。


class MyHomeBody extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return Stack(
            children: <Widget>[
                Container(
                   color: Colors.purple,
                   width: 300,
                   height: 300,
                ),
                Positioned(
                   left: 20,
                   top: 20,
                   child: Icon(Icons.favorite, size: 50, color: Colors.white)
                ),
                Positioned(
                  bottom: 20,
                  right: 20,
                  child: Text("你好啊,李银河", style: TextStyle(fontSize: 20, color: Colors.white)),
                )
            ],
       );
    }
}


提示已定位的组件只能在堆栈中使用


目录
相关文章
|
6月前
|
编解码 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局
【4月更文挑战第30天】Flutter框架助力移动应用实现响应式设计与自适应布局,通过层次化布局系统和`Widget`树管理,结合`BoxConstraints`定义尺寸范围,实现自适应。利用`MediaQuery`获取设备信息,调整布局以适应不同屏幕。`FractionallySizedBox`按比例设定尺寸,`LayoutBuilder`动态计算布局。借助这些工具,开发者能创建跨屏幕尺寸、方向兼容的应用,提升用户体验。
156 0
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局
|
9天前
|
开发者 容器
Flutter&鸿蒙next 布局架构原理详解
本文详细介绍了 Flutter 中的主要布局方式,包括 Row、Column、Stack、Container、ListView 和 GridView 等布局组件的架构原理及使用场景。通过了解这些布局 Widget 的基本概念、关键属性和布局原理,开发者可以更高效地构建复杂的用户界面。此外,文章还提供了布局优化技巧,帮助提升应用性能。
72 4
|
9天前
|
容器
深入理解 Flutter 鸿蒙版的 Stack 布局:适配屏幕与层叠样式布局
Flutter 的 Stack 布局组件允许你将多个子组件层叠在一起,实现复杂的界面效果。本文介绍了 Stack 的基本用法、核心概念(如子组件层叠、Positioned 组件和对齐属性),以及如何使用 MediaQuery 和 LayoutBuilder 实现响应式设计。通过示例展示了照片展示与文字描述、动态调整层叠布局等高级用法,帮助你构建更加精美和实用的 Flutter 应用。
92 2
|
22天前
|
容器
Flutter&鸿蒙next 布局架构原理详解
Flutter&鸿蒙next 布局架构原理详解
|
27天前
|
Android开发 开发者 容器
flutter:&UI布局 (六)
本文档介绍了Flutter中的UI布局方式,包括线性布局(如Column和Row)、非线性布局(如Stack、Flex、Positioned)以及Wrap布局等。通过具体示例代码展示了如何使用这些布局组件来构建灵活多变的用户界面,例如使用Column垂直排列文本、使用Stack叠加组件、以及利用Wrap实现自动换行的按钮布局等。
|
6月前
|
开发框架 前端开发 数据安全/隐私保护
【Flutter 前端技术开发专栏】Flutter 中的布局与样式设计
【4月更文挑战第30天】本文探讨了Flutter的布局和样式设计,关键点包括:1) 布局基础如Column、Row和Stack用于创建复杂结构;2) Container、Center和Expanded等常用组件的作用;3) Theme和Decoration实现全局样式和组件装饰;4) 实战应用如登录界面和列表页面的构建;5) 响应式布局利用MediaQuery和弹性组件适应不同屏幕;6) 性能优化,避免过度复杂设计。了解并掌握这些,有助于开发者创建高效美观的Flutter应用。
179 0
【Flutter 前端技术开发专栏】Flutter 中的布局与样式设计
|
4月前
|
容器
flutter 布局管理【详解】
flutter 布局管理【详解】
37 3
|
5月前
|
Dart 开发者
Flutter 中的 RenderObjectToWidgetAdapter 小部件:全面指南
Flutter 中的 RenderObjectToWidgetAdapter 小部件:全面指南
28 2
|
4月前
Flutter-自定义折叠流布局实现
Flutter-自定义折叠流布局实现
76 0
|
5月前
|
开发者
Flutter 中的 ChipTheme 小部件:全面指南
Flutter 中的 ChipTheme 小部件:全面指南
52 3