美文网首页程序员
[Flutter]flutter基础之组件基础(七)

[Flutter]flutter基础之组件基础(七)

作者: 陌问MW | 来源:发表于2020-04-09 10:50 被阅读0次

    一、概述

    因为很多的基础小部件( Widget ) 依赖于布局 Widget ,所以在本套基础讲解中,会穿插各种 Widget 的说明,并没有按照一定的分组顺序进行讲解。就是用到什么讲解什么,但是力争做到讲解的够清晰。所以现在开始说明一些基础的布局 Widget, 后续很多其他的 Widget 在使用中会依赖于或用到布局的 Widget ,所以在此先进行说明。

    二 、Container Widget

    容器 Widget ,其是一个可以设置宽高,边距,装饰等的 Widget ,有一个子 Widget 属性 child 。如果没有设置子 Widget ,容器会尽可能大的展示。它继承自 StatelessWidget ,是一个无状态的 Widget 。构造方法如下:

    Container({
      Key key,
      //AlignmentGeometry类型可选命名参数,容器内子Widget如何对其,使用其子类Alignment
      this.alignment,
      //EdgeInsetsGeometry类型可选命名参数,设置容器内边距
      this.padding,
      //Color类型可选命名参数,容器填充色
      Color color,
      //Decoration类型可选命名参数,绘制在child子Widget后面的装饰,使用BoxDecoration
      Decoration decoration,
      //Decoration类型可选命名参数,绘制在child子Widget前面的装饰,使用BoxDecoration
      this.foregroundDecoration,
      //double类型可选命名参数,容器的宽度
      double width,
      //double类型可选命名参数,容器的高度
      double height,
      //BoxConstraints类型可选命名参数,对child设置的Widget的约束
      BoxConstraints constraints,
      //EdgeInsetsGeometry类型可选命名参数,设置容器外边距
      this.margin,
      //Matrix4类型可选命名参数,在绘制容器之前要应用的转换矩阵
      this.transform,
      //Widget类型可选命名参数,容器包含的子Widget
      this.child,
    })
    

    其中 colordecoration 不能同时设置。

    Decoration 是一个抽象类,这里需要使用 BoxDecoration ,是一个用于设置如何绘制盒子的不可变的的描述。盒子的主体是分层绘制的。 最底层是颜色,它填充了框。 在此之上的是渐变,渐变也填充了该框。 最后是图像,其精确对齐由 DecorationImage 类控制。边框涂在身体上,阴影自然在其下方绘制。其构造方法如下:

    const BoxDecoration({
      //Color类型可选命名参数,填充背景色
      this.color,
      //DecorationImage类型可选命名参数,在背景或渐变上绘制的图像
      this.image,
      //BoxBorder类型可选命名参数,边框设置
      this.border,
      //BorderRadiusGeometry类型可选命名参数,设置圆角
      this.borderRadius,
      //List<BoxShadow>类型可选命名参数,盒子后面的盒子投射的阴影列表
      this.boxShadow,
      //Gradient类型可选命名参数,填充框时使用的渐变
      this.gradient,
      //BlendMode类型可选命名参数,应用于框的颜色或渐变背景的混合模式
      this.backgroundBlendMode,
      //BoxShape类型可选命名参数,将背景颜色、渐变和图像填充到并作为boxShadow投射的形状
      this.shape = BoxShape.rectangle,
    })
    

    Container 基本使用方式如下:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(    //Container
            color: Colors.yellow,
          ),
        );
      }
    }
    

    此时的 Container 会充满整个屏幕,尽可能大。

    其它属性设置

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(              //Container
            width: 300,
            height: 200,
            child: Text("这是一个文本",),
            alignment: Alignment.topCenter,  //子Widget的相对于父级Container的对齐方式
            padding: EdgeInsets.all(20),   //设置内边距,文本的每个边外都有20的边距
            margin: EdgeInsets.all(50),   //设置外边距,Container每个边外有50的外边距
            color: Colors.yellow,    //填充色
            transform: Matrix4.rotationZ(0.2),   //围绕Z轴旋转指定弧度
            foregroundDecoration: BoxDecoration(
              image: DecorationImage(
                image: NetworkImage("http://www.mwpush.com/uploads/avatar.png"),
                fit: BoxFit.fill
              ),
              border: Border.all(
                width: 5,
                color: Colors.blue
              ),
            ),
          ),
        );
      }
    }
    

    效果如下:

    20203201145.jpg

    foregroundDecoration 用于设置前景装饰效果,所以如果有重叠,当加载图片时会覆盖 Container 本身的内容。如果不希望覆盖,使用背景装饰效果 decoration 即可,使用方式相同,只是使用 decoration 时不能使用 color ,使用如下:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            width: 300,
            height: 200,
            child: Text("这是一个文本",),
            alignment: Alignment.topCenter,  //子Widget的相对于父级Container的对齐方式
            padding: EdgeInsets.all(20),   //设置内边距,文本的每个边外都有20的边距
            margin: EdgeInsets.all(50),   //设置外边距,Container每个边外有50的外边距
            transform: Matrix4.rotationZ(0.2),   //围绕Z轴旋转指定弧度
            constraints: BoxConstraints(    //设置最大最小约束
              minHeight: 300,
              minWidth: 300,
              maxHeight: 400,
              maxWidth: 400,
            ),
            decoration: BoxDecoration(      //decoration
              image: DecorationImage(
                image: NetworkImage("http://www.mwpush.com/uploads/avatar.png"),
                fit: BoxFit.fill
              ),
              border: Border.all(
                width: 5,
                color: Colors.blue
              ),
              borderRadius: BorderRadius.all(Radius.circular(10)),  //设置圆角
            ),
          ),
        );
      }
    }
    

    效果如下:

    2020321827.jpg

    BoxDecoration 还可以设置渐变色等属性。

    三、Center Widget

    Center 是将子 Widget 放置于其中心的 Widget 。如果其宽高没有设置,则其会尽可能大的展示。可通过设置宽度与高度因子来控制大小。比如设置宽度因子后,Center 的宽度值为子 Widget 的宽度乘以宽度因子的值。宽度与高度因子的值必须为正数。其构造方法如下:

    const Center({
      Key key, 
      //double类型可选命名参数,宽度因子
      double widthFactor, 
      //double类型可选命名参数,高度因子
      double heightFactor, 
      //Widget类型可选命名参数,要显示的子Widget
      Widget child 
    })
    

    使用如下:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            color: Colors.yellowAccent,
            child: Center(              //Center
              widthFactor: 2,
              heightFactor: 2,
              child: Container(
                color: Colors.red,
                child: Text("中心文本",),
              ),
            ),
          )
        );
      }
    }
    

    这里为了看清显示的效果,使用了 Container Widget 来包裹 CenterCenterchild Widget ,因为 Container 可以设置填充色,便于区分。效果如下:

    2020322752.jpg

    四、Padding Widget

    Padding 是用来设置内填充(内边距)的 Widget ,在 Container 中也可以设置 Containerpadding ,两者并没有区别。Container 是将多个单独的 Widget 进行组合使用,需要时只需设置相应的属性即可。作用是通过设置内边距的大小使其进行膨胀,在其子 Widget 周围创造出一定的空间。其构造函数方法如下:

    const Padding({
      Key key,
      //EdgeInsetsGeometry类型必传参数,内边距
      @required this.padding,
      //Widget类型可选命名参数,要显示的Widget
      Widget child,
    })
    

    使用方法如下,与上述 Center 实现效果差不多,代码中的 Container 也是为了使效果看的更清晰:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            color: Colors.yellow,
            child: Padding(             //Padding
              padding: EdgeInsets.all(50),
              child: Container(
                color: Colors.red,
                child: Text("Padding"),
              ),
            ),
          ),
        );
      }
    }
    

    五、Align Widget

    Align 可以设置其子 Widget 相对自己的对齐方式,并可以根据子 Widget 的大小调整其自己的大小。其可以设置宽度和高度因子,如果不设置,则其会尽可能的大的展示,如果设置,比如设置宽度因子,则 Align 的宽度将是其子 Widget 的宽度乘以宽度因子。构造方法如下:

    const Align({
      Key key,
      //AlignmentGeometry类型可选命名参数,设置如何对齐,AlignmentGeometry为抽象类,
      //通常使用Alignment或FractionalOffset
      this.alignment = Alignment.center,
      //double类型可选命名参数,宽度因子
      this.widthFactor,
      //double类型可选命名参数,高度因子
      this.heightFactor,
      //Widget类型可选命名参数,要显示的Widget
      Widget child,
    })
    

    AlignCenter 类似,不同的是 Align 可以设置其子 Widget 相对于自己的对齐方式,而 Center 则是居中对齐。

    Alignment 在此用来设置对其方式,其定义的是一个矩形中的点。其提供了几种对齐方式可以直接使用,如下:

    /// 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() 构造方法,如下:

    //x,y均为double类型的必传参数,用于定义一个点的x和y轴值
    const Alignment(this.x, this.y)
    

    所以可以直接使用构造函数定义需要通过哪个点对齐,如下:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            color: Colors.yellow,
            child: Align(
              child: Container(child: Text("Align"), color: Colors.red,),
              alignment: Alignment(0.2, 0.5),
              widthFactor: 10,
              heightFactor: 10,
            ),
          ),
        );
      }
    }
    

    Alignment(0.0, 0.0) 表示矩形的中心点。从 -1.0 到 +1.0 的距离是从矩形的一侧到矩形的另一侧的距离。 因此,水平(或垂直)2.0 个单位等于矩形的宽度(或高度)。Alignment(-1.0, -1.0) 表示矩形的左上方,Alignment(1.0, 1.0) 表示矩形的右下角。Alignment(0.0, 3.0) 表示一个点,该点相对于矩形水平居中,垂直于矩形底部低于矩形的高度。Alignment(0.0, -0.5)表示相对于矩形水平居中且顶部边缘与中心之间垂直居中的点。

    以上面的代码为例,其对齐的点的计算方法为( 0.2*Text的宽度/2 + Text的宽度/2, 0.5*Text的高度/2+Text的高度/2 )

    Alignment 使用的坐标系,其原点位于容器的中心点。

    FractionalOffset 用来定义一个偏移量,其也提供了几个常用的值,如下:

    /// The top left corner.
    static const FractionalOffset topLeft = FractionalOffset(0.0, 0.0);
    /// The center point along the top edge.
    static const FractionalOffset topCenter = FractionalOffset(0.5, 0.0);
    /// The top right corner.
    static const FractionalOffset topRight = FractionalOffset(1.0, 0.0);
    /// The center point along the left edge.
    static const FractionalOffset centerLeft = FractionalOffset(0.0, 0.5);
    /// The center point, both horizontally and vertically.
    static const FractionalOffset center = FractionalOffset(0.5, 0.5);
    /// The center point along the right edge.
    static const FractionalOffset centerRight = FractionalOffset(1.0, 0.5);
    /// The bottom left corner.
    static const FractionalOffset bottomLeft = FractionalOffset(0.0, 1.0);
    /// The center point along the bottom edge.
    static const FractionalOffset bottomCenter = FractionalOffset(0.5, 1.0);
    /// The bottom right corner.
    static const FractionalOffset bottomRight = FractionalOffset(1.0, 1.0);
    

    可以看到,其与 Alignment 类似,不同之处在于 Alignment() 定义的是一个点(计算方法在上面),而 FractionalOffset() 定义的是两个点,这两个点是单独确定的。对于当前 Widget ,这里为 Text ,其点的计算方式为:(0.2*Text的宽度, 0.5*Text的高度) 。对于父级 Widget ,这里为 Container 则是 (0.2*Container的宽度, 0.5*Container的高度) 。最后使两个点重合,即将 Text 的点移动到 Container 定位的点处。使用

    FractionalOffset 时,其原点位于容器的左上角。

    此外,除了提供 FractionalOffset(double x, double y) 构造方法,另外还提供了如下两个构造方法:

    factory FractionalOffset.fromOffsetAndSize(Offset offset, Size size) {
      assert(size != null);
      assert(offset != null);
      return FractionalOffset(
        offset.dx / size.width,
        offset.dy / size.height,
      );
    }
    
    factory FractionalOffset.fromOffsetAndRect(Offset offset, Rect rect) {
      return FractionalOffset.fromOffsetAndSize(
        offset - rect.topLeft,
        rect.size,
      );
    }
    

    六、Row Widget

    Row 是一个可以同时显示多个子 Widget 的 Widget ,这些子 Widget 以水平方式进行排列。Row Widget 不是一个可以滚动的 Widget ,如果水平显示的子 Widget 的总范围超出了可用空间会抛出异常。如果有需要进行水平或垂直方向的滚动操作,考虑使用 ListView ,后面会讲到。Row 的构造方法如下:

    Row({
      Key key,
      //MainAxisAlignment类型可选命名参数,如何沿着主轴放置子Widget
      MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
      //MainAxisSize类型可选命名参数,主轴上应占用多少空间,该值传入最大化还是最小化可用空间
      MainAxisSize mainAxisSize = MainAxisSize.max,
      //CrossAxisAlignment类型可选命名参数,如何沿着次轴放置子Widget
      CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
      //TextDirection类型可选命名参数,设置子Widget横向的排列方向,默认为环境方向
      TextDirection textDirection,
      //VerticalDirection类型可选命名参数,设置子Widget纵向的排列顺序以及如何解释垂直方向的开始和结束
      VerticalDirection verticalDirection = VerticalDirection.down,
      //TextBaseline类型可选命名参数,如果根据基线对齐项目,使用哪个基线
      TextBaseline textBaseline,
      //List<Widget>类型可选命名参数,要显示的子Widget列表
      List<Widget> children = const <Widget>[],
    })
    

    MainAxisAlignment 用于设置子 Widget 在主轴(这里是水平方向)上的排列方式,是一个枚举类型,有如下值:

    enum MainAxisAlignment {
      //子Widget放置在尽可能靠近主轴起点的位置。如果在水平方向使用,则必须使
      //用TextDirection来确定起点是左侧还是右侧。如果在垂直方向上使用此值,
      //则VerticalDirection必须可用以确定起点是顶部还是底部
      start,
    
        //子Widget放置在尽可能靠近主轴末端的位置。如果在水平方向上使用此值,则必须使
      //用TextDirection来确定末端是左侧还是右侧。如果在垂直方向上使用此值,则必须
      //使用VerticalDirection来确定末端是顶部还是底部
      end,
    
      //子Widget放置在尽可能靠近主轴的中心
      center,
    
      //子Widget均匀的放置在可用空间内
      spaceBetween,
    
      //将自由空间平均放置在两个子Widget之间,以及第一个和最后一个Widget前后的一半空间
      spaceAround,
    
      //在子Widget之间以及第一个Widget和最后一个Widget之前和之后均匀地放置自由空间
      spaceEvenly,
    }
    

    CrossAxisAlignment 用于设置子 Widget 在次轴(这里是垂直方向)上的排列方式,是一个枚举类型,有如下值:

    enum CrossAxisAlignment {
      //子Widget放置在尽可能靠近次轴起点的位置。如果在水平方向上使用此值,则必须使
      //用TextDirection来确定起点是左侧还是右侧。如果在垂直方向上使用此值,
      //则VerticalDirection必须可用以确定起点是顶部还是底部
      start,
    
      //子Widget放置在尽可能靠近次轴末端的位置。如果在水平方向上使用此值,则必须使
      //用TextDirection来确定末端是左侧还是右侧。如果在垂直方向上使用此值,则必须
      //使用VerticalDirection来确定末端是顶部还是底部
      end,
    
      //子Widget放置在尽可能靠近次轴的中心
      center,
    
      //子Widget填满次轴
      stretch,
    
      //在次轴上放置子Widget,使其与基线对齐,使用此值需要设置textBaseline
      baseline,
    }
    

    VerticalDirection 用于设置垂直的排列方向,是一个枚举类型值,有如下值:

    enum VerticalDirection {
      //盒子应从底部开始,并垂直向上堆叠。“开始”在底部,“结束”在顶部。
      up,
      
      //盒子应从顶部开始,并垂直向下堆叠。“开始”在顶部,“结束”在底部。
      down,
    }
    

    Row 的使用方式如下:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            height: 100,
            color: Colors.yellow,
            child: Row(                         //Row
              textBaseline: TextBaseline.alphabetic,
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: <Widget>[
    //            Image.network("http://www.mwpush.com/uploads/avatar.png"),
                Container(child: Text("Row1"), color: Colors.red,),
                Text("Row2"),
                Text("Row3"),
              ],
            ),
          ),
        );
      }
    }
    

    效果如下:

    20203231204.jpg

    七、Column Widget

    Column 是一个可以同时显示多个子 Widget 的 Widget ,这些子 Widget 以垂直方式进行排列。Column Widget 不是一个可以滚动的 Widget ,如果垂直显示的子 Widget 的总范围超出了可用空间会抛出异常。如果有需要进行水平或垂直方向的滚动操作,考虑使用 ListViewColumn 的构造方法如下:

    Column({
      Key key,
      //MainAxisAlignment类型可选命名参数,如何沿着主轴放置子Widget
      MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
      //MainAxisSize类型可选命名参数,主轴上应占用多少空间,该值传入最大化还是最小化可用空间
      MainAxisSize mainAxisSize = MainAxisSize.max,
      //CrossAxisAlignment类型可选命名参数,如何沿着次轴放置子Widget
      CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
      //TextDirection类型可选命名参数,设置子Widget横向的排列方向,默认为环境方向
      TextDirection textDirection,
      //VerticalDirection类型可选命名参数,设置子Widget纵向的排列顺序以及如何解释垂直方向的开始和结束
      VerticalDirection verticalDirection = VerticalDirection.down,
      //TextBaseline类型可选命名参数,如果根据基线对齐项目,使用哪个基线
      TextBaseline textBaseline,
      //List<Widget>类型可选命名参数,要显示的子Widget列表
      List<Widget> children = const <Widget>[],
    })
    

    构造方法与 Row 相同,只是排列的基准不同。使用如下:

    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            width: 500,
            height: 200,
            color: Colors.yellow,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
    //            Image.network("http://www.mwpush.com/uploads/avatar.png"),
                Container(child: Text("Row1"), color: Colors.red,),
                Text("Row2"),
                Text("Row3"),
              ],
            ),
          ),
        );
      }
    }
    

    效果如下:

    20203231212.jpg

    更多内容,请关注公众号持续关注。

    wchatq2.png

    相关文章

      网友评论

        本文标题:[Flutter]flutter基础之组件基础(七)

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