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

一、概述

因為很多的基礎(chǔ)小部件( Widget ) 依賴于布局 Widget ,所以在本套基礎(chǔ)講解中,會穿插各種 Widget 的說明,并沒有按照一定的分組順序進(jìn)行講解。就是用到什么講解什么,但是力爭做到講解的夠清晰。所以現(xiàn)在開始說明一些基礎(chǔ)的布局 Widget, 后續(xù)很多其他的 Widget 在使用中會依賴于或用到布局的 Widget ,所以在此先進(jìn)行說明。

二 、Container Widget

容器 Widget ,其是一個可以設(shè)置寬高,邊距,裝飾等的 Widget ,有一個子 Widget 屬性 child 。如果沒有設(shè)置子 Widget ,容器會盡可能大的展示。它繼承自 StatelessWidget ,是一個無狀態(tài)的 Widget 。構(gòu)造方法如下:

Container({
  Key key,
  //AlignmentGeometry類型可選命名參數(shù),容器內(nèi)子Widget如何對其,使用其子類Alignment
  this.alignment,
  //EdgeInsetsGeometry類型可選命名參數(shù),設(shè)置容器內(nèi)邊距
  this.padding,
  //Color類型可選命名參數(shù),容器填充色
  Color color,
  //Decoration類型可選命名參數(shù),繪制在child子Widget后面的裝飾,使用BoxDecoration
  Decoration decoration,
  //Decoration類型可選命名參數(shù),繪制在child子Widget前面的裝飾,使用BoxDecoration
  this.foregroundDecoration,
  //double類型可選命名參數(shù),容器的寬度
  double width,
  //double類型可選命名參數(shù),容器的高度
  double height,
  //BoxConstraints類型可選命名參數(shù),對child設(shè)置的Widget的約束
  BoxConstraints constraints,
  //EdgeInsetsGeometry類型可選命名參數(shù),設(shè)置容器外邊距
  this.margin,
  //Matrix4類型可選命名參數(shù),在繪制容器之前要應(yīng)用的轉(zhuǎn)換矩陣
  this.transform,
  //Widget類型可選命名參數(shù),容器包含的子Widget
  this.child,
})

其中 colordecoration 不能同時設(shè)置。

Decoration 是一個抽象類,這里需要使用 BoxDecoration ,是一個用于設(shè)置如何繪制盒子的不可變的的描述。盒子的主體是分層繪制的。 最底層是顏色,它填充了框。 在此之上的是漸變,漸變也填充了該框。 最后是圖像,其精確對齊由 DecorationImage 類控制。邊框涂在身體上,陰影自然在其下方繪制。其構(gòu)造方法如下:

const BoxDecoration({
  //Color類型可選命名參數(shù),填充背景色
  this.color,
  //DecorationImage類型可選命名參數(shù),在背景或漸變上繪制的圖像
  this.image,
  //BoxBorder類型可選命名參數(shù),邊框設(shè)置
  this.border,
  //BorderRadiusGeometry類型可選命名參數(shù),設(shè)置圓角
  this.borderRadius,
  //List<BoxShadow>類型可選命名參數(shù),盒子后面的盒子投射的陰影列表
  this.boxShadow,
  //Gradient類型可選命名參數(shù),填充框時使用的漸變
  this.gradient,
  //BlendMode類型可選命名參數(shù),應(yīng)用于框的顏色或漸變背景的混合模式
  this.backgroundBlendMode,
  //BoxShape類型可選命名參數(shù),將背景顏色、漸變和圖像填充到并作為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 會充滿整個屏幕,盡可能大。

其它屬性設(shè)置

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),   //設(shè)置內(nèi)邊距,文本的每個邊外都有20的邊距
        margin: EdgeInsets.all(50),   //設(shè)置外邊距,Container每個邊外有50的外邊距
        color: Colors.yellow,    //填充色
        transform: Matrix4.rotationZ(0.2),   //圍繞Z軸旋轉(zhuǎn)指定弧度
        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 用于設(shè)置前景裝飾效果,所以如果有重疊,當(dāng)加載圖片時會覆蓋 Container 本身的內(nèi)容。如果不希望覆蓋,使用背景裝飾效果 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),   //設(shè)置內(nèi)邊距,文本的每個邊外都有20的邊距
        margin: EdgeInsets.all(50),   //設(shè)置外邊距,Container每個邊外有50的外邊距
        transform: Matrix4.rotationZ(0.2),   //圍繞Z軸旋轉(zhuǎn)指定弧度
        constraints: BoxConstraints(    //設(shè)置最大最小約束
          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)),  //設(shè)置圓角
        ),
      ),
    );
  }
}

效果如下:

2020321827.jpg

BoxDecoration 還可以設(shè)置漸變色等屬性。

三、Center Widget

Center 是將子 Widget 放置于其中心的 Widget 。如果其寬高沒有設(shè)置,則其會盡可能大的展示??赏ㄟ^設(shè)置寬度與高度因子來控制大小。比如設(shè)置寬度因子后,Center 的寬度值為子 Widget 的寬度乘以寬度因子的值。寬度與高度因子的值必須為正數(shù)。其構(gòu)造方法如下:

const Center({
  Key key, 
  //double類型可選命名參數(shù),寬度因子
  double widthFactor, 
  //double類型可選命名參數(shù),高度因子
  double heightFactor, 
  //Widget類型可選命名參數(shù),要顯示的子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 可以設(shè)置填充色,便于區(qū)分。效果如下:

2020322752.jpg

四、Padding Widget

Padding 是用來設(shè)置內(nèi)填充(內(nèi)邊距)的 Widget ,在 Container 中也可以設(shè)置 Containerpadding ,兩者并沒有區(qū)別。Container 是將多個單獨的 Widget 進(jìn)行組合使用,需要時只需設(shè)置相應(yīng)的屬性即可。作用是通過設(shè)置內(nèi)邊距的大小使其進(jìn)行膨脹,在其子 Widget 周圍創(chuàng)造出一定的空間。其構(gòu)造函數(shù)方法如下:

const Padding({
  Key key,
  //EdgeInsetsGeometry類型必傳參數(shù),內(nèi)邊距
  @required this.padding,
  //Widget類型可選命名參數(shù),要顯示的Widget
  Widget child,
})

使用方法如下,與上述 Center 實現(xiàn)效果差不多,代碼中的 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 可以設(shè)置其子 Widget 相對自己的對齊方式,并可以根據(jù)子 Widget 的大小調(diào)整其自己的大小。其可以設(shè)置寬度和高度因子,如果不設(shè)置,則其會盡可能的大的展示,如果設(shè)置,比如設(shè)置寬度因子,則 Align 的寬度將是其子 Widget 的寬度乘以寬度因子。構(gòu)造方法如下:

const Align({
  Key key,
  //AlignmentGeometry類型可選命名參數(shù),設(shè)置如何對齊,AlignmentGeometry為抽象類,
  //通常使用Alignment或FractionalOffset
  this.alignment = Alignment.center,
  //double類型可選命名參數(shù),寬度因子
  this.widthFactor,
  //double類型可選命名參數(shù),高度因子
  this.heightFactor,
  //Widget類型可選命名參數(shù),要顯示的Widget
  Widget child,
})

AlignCenter 類似,不同的是 Align 可以設(shè)置其子 Widget 相對于自己的對齊方式,而 Center 則是居中對齊。

Alignment 在此用來設(shè)置對其方式,其定義的是一個矩形中的點。其提供了幾種對齊方式可以直接使用,如下:

/// 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() 構(gòu)造方法,如下:

//x,y均為double類型的必傳參數(shù),用于定義一個點的x和y軸值
const Alignment(this.x, this.y)

所以可以直接使用構(gòu)造函數(shù)定義需要通過哪個點對齊,如下:

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 的距離是從矩形的一側(cè)到矩形的另一側(cè)的距離。 因此,水平(或垂直)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 使用的坐標(biāo)系,其原點位于容器的中心點。

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() 定義的是兩個點,這兩個點是單獨確定的。對于當(dāng)前 Widget ,這里為 Text ,其點的計算方式為:(0.2*Text的寬度, 0.5*Text的高度) 。對于父級 Widget ,這里為 Container 則是 (0.2*Container的寬度, 0.5*Container的高度) 。最后使兩個點重合,即將 Text 的點移動到 Container 定位的點處。使用

FractionalOffset 時,其原點位于容器的左上角。

此外,除了提供 FractionalOffset(double x, double y) 構(gòu)造方法,另外還提供了如下兩個構(gòu)造方法:

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 以水平方式進(jìn)行排列。Row Widget 不是一個可以滾動的 Widget ,如果水平顯示的子 Widget 的總范圍超出了可用空間會拋出異常。如果有需要進(jìn)行水平或垂直方向的滾動操作,考慮使用 ListView ,后面會講到。Row 的構(gòu)造方法如下:

Row({
  Key key,
  //MainAxisAlignment類型可選命名參數(shù),如何沿著主軸放置子Widget
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  //MainAxisSize類型可選命名參數(shù),主軸上應(yīng)占用多少空間,該值傳入最大化還是最小化可用空間
  MainAxisSize mainAxisSize = MainAxisSize.max,
  //CrossAxisAlignment類型可選命名參數(shù),如何沿著次軸放置子Widget
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  //TextDirection類型可選命名參數(shù),設(shè)置子Widget橫向的排列方向,默認(rèn)為環(huán)境方向
  TextDirection textDirection,
  //VerticalDirection類型可選命名參數(shù),設(shè)置子Widget縱向的排列順序以及如何解釋垂直方向的開始和結(jié)束
  VerticalDirection verticalDirection = VerticalDirection.down,
  //TextBaseline類型可選命名參數(shù),如果根據(jù)基線對齊項目,使用哪個基線
  TextBaseline textBaseline,
  //List<Widget>類型可選命名參數(shù),要顯示的子Widget列表
  List<Widget> children = const <Widget>[],
})

MainAxisAlignment 用于設(shè)置子 Widget 在主軸(這里是水平方向)上的排列方式,是一個枚舉類型,有如下值:

enum MainAxisAlignment {
  //子Widget放置在盡可能靠近主軸起點的位置。如果在水平方向使用,則必須使
  //用TextDirection來確定起點是左側(cè)還是右側(cè)。如果在垂直方向上使用此值,
  //則VerticalDirection必須可用以確定起點是頂部還是底部
  start,

    //子Widget放置在盡可能靠近主軸末端的位置。如果在水平方向上使用此值,則必須使
  //用TextDirection來確定末端是左側(cè)還是右側(cè)。如果在垂直方向上使用此值,則必須
  //使用VerticalDirection來確定末端是頂部還是底部
  end,

  //子Widget放置在盡可能靠近主軸的中心
  center,

  //子Widget均勻的放置在可用空間內(nèi)
  spaceBetween,

  //將自由空間平均放置在兩個子Widget之間,以及第一個和最后一個Widget前后的一半空間
  spaceAround,

  //在子Widget之間以及第一個Widget和最后一個Widget之前和之后均勻地放置自由空間
  spaceEvenly,
}

CrossAxisAlignment 用于設(shè)置子 Widget 在次軸(這里是垂直方向)上的排列方式,是一個枚舉類型,有如下值:

enum CrossAxisAlignment {
  //子Widget放置在盡可能靠近次軸起點的位置。如果在水平方向上使用此值,則必須使
  //用TextDirection來確定起點是左側(cè)還是右側(cè)。如果在垂直方向上使用此值,
  //則VerticalDirection必須可用以確定起點是頂部還是底部
  start,

  //子Widget放置在盡可能靠近次軸末端的位置。如果在水平方向上使用此值,則必須使
  //用TextDirection來確定末端是左側(cè)還是右側(cè)。如果在垂直方向上使用此值,則必須
  //使用VerticalDirection來確定末端是頂部還是底部
  end,

  //子Widget放置在盡可能靠近次軸的中心
  center,

  //子Widget填滿次軸
  stretch,

  //在次軸上放置子Widget,使其與基線對齊,使用此值需要設(shè)置textBaseline
  baseline,
}

VerticalDirection 用于設(shè)置垂直的排列方向,是一個枚舉類型值,有如下值:

enum VerticalDirection {
  //盒子應(yīng)從底部開始,并垂直向上堆疊?!伴_始”在底部,“結(jié)束”在頂部。
  up,
  
  //盒子應(yīng)從頂部開始,并垂直向下堆疊。“開始”在頂部,“結(jié)束”在底部。
  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 以垂直方式進(jìn)行排列。Column Widget 不是一個可以滾動的 Widget ,如果垂直顯示的子 Widget 的總范圍超出了可用空間會拋出異常。如果有需要進(jìn)行水平或垂直方向的滾動操作,考慮使用 ListViewColumn 的構(gòu)造方法如下:

Column({
  Key key,
  //MainAxisAlignment類型可選命名參數(shù),如何沿著主軸放置子Widget
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  //MainAxisSize類型可選命名參數(shù),主軸上應(yīng)占用多少空間,該值傳入最大化還是最小化可用空間
  MainAxisSize mainAxisSize = MainAxisSize.max,
  //CrossAxisAlignment類型可選命名參數(shù),如何沿著次軸放置子Widget
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  //TextDirection類型可選命名參數(shù),設(shè)置子Widget橫向的排列方向,默認(rèn)為環(huán)境方向
  TextDirection textDirection,
  //VerticalDirection類型可選命名參數(shù),設(shè)置子Widget縱向的排列順序以及如何解釋垂直方向的開始和結(jié)束
  VerticalDirection verticalDirection = VerticalDirection.down,
  //TextBaseline類型可選命名參數(shù),如果根據(jù)基線對齊項目,使用哪個基線
  TextBaseline textBaseline,
  //List<Widget>類型可選命名參數(shù),要顯示的子Widget列表
  List<Widget> children = const <Widget>[],
})

構(gòu)造方法與 Row 相同,只是排列的基準(zhǔn)不同。使用如下:

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容