[Flutter]flutter基礎之組件基礎(七)

一、概述

因為很多的基礎小部件( 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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一、Image Widget Image Widget 是 Flutter 中用來顯示圖片的小部件。支持以下圖像格...
    陌問MW閱讀 4,140評論 0 5
  • 官方簡介中,說 Container 組件是一個方便繪制、定位和調整子組件大小的組件。首先 Container 會在...
    竇豆逗閱讀 1,101評論 0 0
  • Flutter布局入門 一、Widget簡介 描述 Fullter的核心思想是用widget 來構建你的 UI 界...
    CYL_f78c閱讀 1,141評論 0 1
  • 知我冷暖, 懂我悲歡; 內心篤定, 心懷美好; 雖然我不是最好的, 卻是獨一無二唯一一個; 確認過眼神, 從此心無...
    慢一點不要緊閱讀 488評論 0 1
  • 在公海里賭博是合法,也不知道有沒有進公海,我們練習上了:21點。 規矩不多說,在賭牌中能深刻地理解“概率”一詞的意...
    妮子的世界閱讀 267評論 0 0