Flutter常用Widget(一)Container

詳細介紹Container的相關使用。

一、簡介

A convenience widget that combines common painting, positioning, and sizing widgets.
一個使用方便的小部件,它融合了常見的繪畫,定位和大小調整。

1、構造函數

  Container({
    Key key,    //
    this.alignment, //對齊方式,作用於child,譬如如果是center,表示child在container裏面居中
    this.padding, //內部間距
    Color color,  //背景色,
    Decoration decoration,  //背景裝飾,與color 不能共存,如需要設置背景,裏面也設置背景的方式。
    this.foregroundDecoration,  //前景裝飾
    double width, //寬度
    double height,  //高度
    BoxConstraints constraints, //容器大小的限制條件,跟寬高的區別是
    this.margin,  //間距,類似於layoutParams 的maring.
    this.transform, //變換,類似於安卓的矩陣變換.
    this.child,   //對應的控件
  });

Container的使用的場景比較廣泛,其他的控件都可以加多一層進行包裝,以此來實現margin、pading等相關功能。
看到其構造函數,有一點可能比較疑惑的,不是有寬高了嗎?爲啥還有個constraints?其實這兩個都是指定容器大小,
但如果同時存在,會以constraints 爲準,其實width、height的最後實現,也是通過constraints來做的。

2、繼承關係


Object (dart.core)
  Diagnosticable (diagnostics.dart)
    DiagnosticableTree (diagnostics.dart)
      Widget (framework.dart)
        StatelessWidget (framework.dart)
          Container (container.dart)

3、繪製過程

  • 最裏層是child
  • child外層由Padding包着
  • 然後添加額外的constraints限制
  • 最後添加margin

組成結構
繪製的時候,首先繪製給定的變換(transform),然後繪製裝飾填充物,接着繪製child,最後將前景裝飾繪製出來。

Container Widget 在沒有子child的情況下,會儘可能地變大,除非傳入的constraints是無邊界的,在這種情況下,container會儘可能地小。
在有child的情況下,會根據child的參數來決定,但如果container 設置了width 、height或者constraints,則會根據這些參數來繪製。

4、佈局實現

因爲Container融合了其他的一些widget,並且這些widget都有各自的佈局行爲,所以Container的佈局方式有一些複雜。
總的來說:容器會嘗試以下操作:

  • 遵守對齊方式,根據子項調整大小,
  • 遵守寬度,高度和約束,
  • 擴展以適配父親,以使其儘可能小

具體來講就是:

如果container沒有孩子,沒有設置寬高,沒有設置constraints,並且父容器設置了constraintsunbounded,那麼container會讓自己儘可能的小;

如果container沒有孩子並且沒有設置對齊方式,但是設置了寬高或者constraints(寬度最後其實都會轉換成constraints去佈局),他會根據自己的constraints和父節點的constraints,儘可能地小;

如果container沒有孩子,沒有寬高沒有constraintsalignment,但是父節點設置了有界的約束,那麼container會儘可能根據父節點的有界約束儘可能地撐大自己;

如果container設置了對齊方式,並且父節點設置了無邊界的約束,那麼container會調節自身尺寸來包住子child;

如果container設置了對齊方式,並且父節點設置了有邊界的約束,那麼container會儘可能地撐大自己(根據父節點的大小),然後將其子child按照設置的alignment進行調整;

如果container只有子child,沒有設置寬高,沒有設置constraints,沒有設置alignment,那麼container就會將父節點的constraints傳遞給孩子,並根據child進行調整;

二、使用方式

1、代碼示例

class ContainerWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      height: 200,
      alignment: Alignment.center,
      margin: EdgeInsets.only(top: 45, left: 120),
      padding: EdgeInsets.all(20),

//      color: Colors.yellow,

      decoration: BoxDecoration(  //背景裝飾
          color: Colors.yellow,
          gradient: RadialGradient( //漸變
            colors: [Colors.red, Colors.orange],
            center: Alignment.center,
            radius: .98,
          ),

          boxShadow: [  //卡片陰影
            BoxShadow(
              color: Colors.black54,
              offset: Offset(2.0, 2.0),
              blurRadius: 4.0
            )
          ]
      ),

      transform: Matrix4.rotationZ(0.2),

      child: Text("520", style: TextStyle(color: Colors.white, fontSize: 40.0), ),
    );
  }

}

2、效果圖

效果圖-w200

這裏面的padding 和maring,如果你做過安卓或者iOS的開發,應該比較容易理解,其實就是一個是內部的空白,一個是外部的空白。

3、適用場景

  • 需要設置背景色;
  • 需要設置圓角;
  • 需要設置背景圖片;
  • 需要設置間距;

三、源碼解析

  @override
  Widget build(BuildContext context) {
    Widget current = child;
    //如果沒有child,並且沒有設置constraints,那麼就創建一個LimitedBox,
    if (child == null && (constraints == null || !constraints.isTight)) {
      current = LimitedBox(
        maxWidth: 0.0,
        maxHeight: 0.0,
        child: ConstrainedBox(constraints: const BoxConstraints.expand()),
      );
    }
    //設置對齊方式
    if (alignment != null)
      current = Align(alignment: alignment, child: current);

    final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
    //設置間距
    if (effectivePadding != null)
      current = Padding(padding: effectivePadding, child: current);
      //設置背景色
    if (decoration != null)
      current = DecoratedBox(decoration: decoration, child: current);
      //設置前景色
    if (foregroundDecoration != null) {
      current = DecoratedBox(
        decoration: foregroundDecoration,
        position: DecorationPosition.foreground,
        child: current,
      );
    }
    //設置約束
    if (constraints != null)
      current = ConstrainedBox(constraints: constraints, child: current);
      //設置margin,其實最終也是包了一層padding來實現;
    if (margin != null)
      current = Padding(padding: margin, child: current);
      //最後,設置變換Transform
    if (transform != null)
      current = Transform(transform: transform, child: current);
    return current;
  }

build方法其實並不複雜,每行做的事情,已經註釋,總的來講,就是不設置約束情況,按照父節點儘可能大,如果有約束,則按照內部的來。

四、參考

https://api.flutter.dev/flutter/widgets/Container-class.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章