Flutter 9種佈局組件(帶詳細案例)

界面佈局主要分爲兩大類:佈局類組件和定位裝飾權重組件,咱們佈局的時候基本都是相互嵌套的git

  • 一、佈局類組件
    • 一、線性佈局組件
    • 二、彈性佈局組件
    • 三、流式佈局組件
    • 四、疊加布局組件
  • 二、定位裝飾權重組件
    • 一、Container
    • 二、SizedBox
    • 三、寬高低:AspectRatio
    • 四、FittedBox&FractionallySizedBox&ContainedBox
    • 五、Expanded、Flexible 和 Spacer

如下是這個 UI 的 widget 樹形圖:github

咱們這裏講由淺及深的聊一下Flutter佈局問題markdown

一、Container

Container是flutter中普遍使用的容器類組件less

構造函數ide

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,
})
複製代碼

屬性函數

  • alignment:child對齊的屬性,能夠設置居中、居左、居右、居上、居下等等。
  • padding:內邊距。width和height包含padding值。
  • color:背景顏色。
  • decoration:設置裝飾,好比邊框、圓角、背景圖片等。不能給Container同時設置decoration和color屬性,若是要同時設置,給decoration設置color就能夠。
  • foregroundDecoration,設置前景裝飾。
  • width:寬度。
  • height:高度。
  • constraints:大小範圍約束,constraints有四個屬性:minWidth、minHeight、maxWidth、maxHeight。
  • margin: 外邊距。
  • transform:變換效果,好比翻轉、旋轉、變形等。
  • child:子組件,能夠不設置。

Container自身尺寸的調節分兩種狀況:oop

  • Container在沒有子節點(children)的時候,會試圖去變得足夠大。除非constraints是unbounded限制,在這種狀況下,Container會試圖去變得足夠小。
  • 帶子節點的Container,會根據子節點尺寸調節自身尺寸,可是Container構造器中若是包含了width、height以及constraints,則會按照構造器中的參數來進行尺寸的調節。

Container(
      child: Text(
        "Hello Flutter", // 文字內容
        style: TextStyle(fontSize: 20.0,color: Colors.amber), // 字體樣式 字體大小
      ),
      alignment: Alignment.topLeft, // 字內容的對齊方式 center居中,centerLeft居中左側 centerRight居中右側
      // bottomCenter 下居中對齊 ,bottomLeft 下左對齊,bottomRight 下右對齊
      // topCenter 上居中對齊,topLeft 上左對齊,topRight 上右對齊
      width: 200,   // 寬
      height: 200,  // 高
      color: Colors.red, //顏色   color和decoration不能夠同時存在
      padding: const EdgeInsets.fromLTRB(20.0,20.0,20.0,20.0), // 邊距 all 包括上下左右  fromLTRB 上下左右分別設置邊距fromLTRB(20.0,20.0,20.0,20.0)
      margin: const EdgeInsets.all(30.0), // 外間距
    );
複製代碼

Decoration(裝飾器)

decoration的屬性很強大,能夠支持背景圖線性或者徑向的漸變,邊框,圓角,陰影等屬性佈局

Flutter的Decoration能夠設置:背景色 背景圖 邊框 圓角 陰影 漸變色 的等屬性,Decoration 是基類,它的子類有下面這些字體

  • BoxDecoration:實現邊框、圓角、陰影、形狀、漸變、背景圖像
  • ShapeDecoration:實現四邊分別指定顏色和寬度、底部線、矩形邊色、圓形邊色、體育場(豎向橢圓)、 角形(八邊角)邊色
  • FlutterLogoDecoration:Flutter圖片
  • UnderlineTabindicator:下劃線
const BoxDecoration({
	this.color,//背景色
	this.image,//圖片
	this.border,//描邊
	this.borderRadius,//圓角大小
	this.boxShadow,//陰影
	this.gradient,//漸變色
	this.backgroundBlendMode,//圖像混合模式
	this.shape = BoxShape.rectangle,//形狀,BoxShape.circle和borderRadius不能同時使用
})
複製代碼

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(top: 50.0, left: 120.0), //容器外填充
      constraints: BoxConstraints.tightFor(width: 200.0, height: 150.0), //卡片大小
      decoration: BoxDecoration(//背景裝飾
          gradient: RadialGradient( //背景徑向漸變
              colors: [Colors.red, Colors.orange],
              center: Alignment.topLeft,
              radius: .98
          ),
          boxShadow: [ //卡片陰影
            BoxShadow(
                color: Colors.black54,
                offset: Offset(2.0, 2.0),
                blurRadius: 4.0
            )
          ]
      ),
      transform: Matrix4.rotationZ(.2), //卡片傾斜變換
      alignment: Alignment.center, //卡片內文字居中
      child: Text( //卡片文字
        "Flutter Demo",
        style: TextStyle(color: Colors.white, fontSize: 40.0),
      ),
    );
  }
}
複製代碼

二、SizedBox

SizedBox: 兩種用法:一是可用來設置兩個widget之間的間距,二是能夠用來限制子組件的大小。flex

Column(
      children: <Widget>[
        SizedBox(height: 30,),
        SizedBox(width: 200,height: 200,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.red,
          ),
        ),
        SizedBox(height: 30,),
        SizedBox(width: 100,height: 100,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.red,
          ),
        )
      ],
    );
複製代碼

能夠看到,代碼中共有4個SizedBox組件,兩個是設置間距的功能,兩個是具備設置約束的功能

三、線性佈局

所謂線性佈局,即指沿水平或垂直方向排布子組件。Flutter中經過Row和Column來實現線性佈局。Row和Column都繼承自Flex,咱們將在彈性佈局一節中詳細介紹Flex。

  • Row 是將子組件以水平方式佈局的組件,
  • Column 是將子組件以垂直方式佈局的組件

項目中 90% 的頁面佈局均可以經過 Row 和 Column 來實現。

一、row

Row(
      children: <Widget>[
        Container(
          height: 50,
          width: 100,
          color: Colors.red,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.green,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.blue,
        ),
      ],
    );
複製代碼

二、column

Column(
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)
複製代碼

三、主軸( MainAxis ) 和 交叉軸( CrossAxis )

在 Row 和 Column 中有一個很是重要的概念:主軸( MainAxis ) 和 交叉軸( CrossAxis ),主軸就是與組件佈局方向一致的軸,交叉軸就是與主軸方向垂直的軸。

具體到 Row 組件,主軸 是水平方向,交叉軸 是垂直方向。而 Column 與 Row 正好相反,主軸 是 垂直方向,交叉軸 是水平方向。

明白了 主軸 和 交叉軸 概念,咱們來看下 mainAxisAlignment 屬性,此屬性表示主軸方向的對齊方式,默認值爲 start,表示從組件的開始處佈局,此處的開始位置和 textDirection 屬性有關,textDirection 表示文本的佈局方向,其值包括 ltr(從左到右) 和 rtl(從右到左),當 textDirection = ltr 時,start 表示左側,當 textDirection = rtl 時,start 表示右側,

spaceAround 和 spaceEvenly 區別是:

  • spaceAround :第一個子控件距開始位置和最後一個子控件距結尾位置是其餘子控件間距的一半。
  • spaceEvenly : 全部間距同樣。

Container(
      decoration: BoxDecoration(border: Border.all(color: Colors.black)),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            height: 50,
            width: 100,
            color: Colors.red,
          ),
          Container(
            height: 100,
            width: 100,
            color: Colors.green,
          ),
          Container(
            height: 150,
            width: 100,
            color: Colors.blue,
          ),
        ],
      ),
    )
複製代碼

四、彈性佈局(Flex)

Row與Column是繼承自Flex的,Flex的大部分功能都在上一個線性佈局中介紹過了。咱們這裏在補充幾個知識點。

  • 一、Flexible:Flexible是一個控制Row、Column、Flex等子組件如何佈局的組件。
  • 二、Expanded:Expanded 繼承字 Flexible,fit 參數固定爲 FlexFit.tight,也就是說 Expanded 必須(強制)填滿剩餘空間
  • 三、Spacer:Spacer 的本質也是 Expanded 的實現的,和Expanded的區別是:Expanded 能夠設置子控件,而 Spacer 的子控件尺寸是0,所以Spacer適用於撐開 Row、Column、Flex 的子控件的空隙

一、Flexible

Flexible 組件能夠控制 Row、Column、Flex 的子控件佔滿父組件,好比,Row 中有3個子組件,兩邊的寬是100,中間的佔滿剩餘的空間

Row(
      children: <Widget>[
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
        Flexible(
            child: Container(
              color: Colors.red,
              height: 50,
            )
        ),
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
      ],
    )
複製代碼

仍是有3個子組件,第一個佔1/6,第二個佔2/6,第三個佔3/6,代碼以下

Column(
      children: <Widget>[
        Flexible(
          flex: 1,
          child: Container(
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('1 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
        Flexible(
          flex: 2,
          child: Container(
            color: Colors.red,
            alignment: Alignment.center,
            child: Text('2 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
        Flexible(
          flex: 3,
          child: Container(
            color: Colors.green,
            alignment: Alignment.center,
            child: Text('3 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
      ],
    )

複製代碼

子組件佔比 = 當前子控件 flex / 全部子組件 flex 之和。 Flexible中 fit 參數表示填滿剩餘空間的方式,說明以下:

  • tight:必須(強制)填滿剩餘空間。
  • loose:儘量大的填滿剩餘空間,可是能夠不填滿。

這2個看上去不是很好理解啊,什麼叫儘量大的填滿剩餘空間?何時填滿,看下面的例子

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
        Flexible(
            child: Container(
              color: Colors.red,
              height: 50,
              child: Text('Container',style: TextStyle(color: Colors.white),),
            )
        ),
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
      ],
    );
  }
}
複製代碼

這段代碼是在最上面代碼的基礎上給中間的紅色Container添加了Text子控件,此時紅色Container就不在充滿空間,再給Container添加對齊方式,代碼以下:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
        Flexible(
            child: Container(
              color: Colors.red,
              height: 50,
              alignment: Alignment.center,
              child: Text('Container',style: TextStyle(color: Colors.white),),
            )
        ),
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
      ],
    );
  }
}
複製代碼

二、Expanded

class Expanded extends Flexible {
  /// Creates a widget that expands a child of a [Row], [Column], or [Flex]
  /// so that the child fills the available space along the flex widget's
  /// main axis.
  const Expanded({
    Key key,
    int flex = 1,
    @required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
}
複製代碼

Expanded 繼承字 Flexible,fit 參數固定爲 FlexFit.tight,也就是說 Expanded 必須(強制)填滿剩餘空間

三、Spacer

Spacer 也是一個權重組件,源代碼以下:

@override
Widget build(BuildContext context) {
  return Expanded(
    flex: flex,
    child: const SizedBox.shrink(),
  );
}
複製代碼

Spacer 的本質也是 Expanded 的實現的,和Expanded的區別是:Expanded 能夠設置子控件,而 Spacer 的子控件尺寸是0,所以Spacer適用於撐開 Row、Column、Flex 的子控件的空隙,用法以下

Row(
  children: <Widget>[
    Container(width: 100,height: 50,color: Colors.green,),
    Spacer(flex: 2,),
    Container(width: 100,height: 50,color: Colors.blue,),
    Spacer(),
    Container(width: 100,height: 50,color: Colors.red,),
  ],
)
複製代碼

三個權重組建總結以下:

  • Spacer 是經過 Expanded 實現的,Expanded繼承自Flexible。
  • 填滿剩餘空間直接使用Expanded更方便。
  • Spacer 用於撐開 Row、Column、Flex 的子組件的空隙。

四、流式佈局(Wrap)

Wrap 爲子組件進行水平或者垂直方向佈局,且當空間用完時,Wrap 會自動換行,也就是流式佈局

Wrap(
      children: List.generate(10, (i) {
        double w = 50.0 + 10 * i;
        return Container(
          color: Colors.primaries[i],
          height: 50,
          width: w,
          child: Text('$i'),
        );
      }),
    )
複製代碼

咱們查看Wrap源碼,咱們發現了一個runAlignment屬性,感受和alignment好像同樣。

runAlignment 屬性控制 Wrap 的交叉抽方向上每一行的對齊方式,下面直接看 runAlignment 6中方式對應的效果圖

runAlignment 和 alignment 的區別:

  • alignment :是主軸方向上對齊方式,做用於每一行。
  • runAlignment :是交叉軸方向上將每一行看做一個總體的對齊方式。

spacing 和 runSpacing 屬性控制Wrap主軸方向和交叉軸方向子控件之間的間隙

Wrap(
      spacing: 30,
      runSpacing: 10,
      children: List.generate(10, (i) {
        double w = 50.0 + 10 * i;
        return Container(
          color: Colors.primaries[i],
          height: 50,
          width: w,
          alignment: Alignment.center,
          child: Text('$i'),
        );
      }),
    )
複製代碼

五、疊加布局(Stack)

疊加布局組件包含 Stack 和 IndexedStack,Stack 組件將子組件疊加顯示,根據子組件的順利依次向上疊加

Stack({
  Key key,
  this.alignment = AlignmentDirectional.topStart,
  this.textDirection,
  this.fit = StackFit.loose,
  this.overflow = Overflow.clip,
  List<Widget> children = const <Widget>[],
})
複製代碼
  • alignment : 指的是子Widget的對其方式,默認狀況是以左上角爲開始點 ,這個屬性是最難理解的,它區分爲使用了Positioned和未使用Positioned定義兩種狀況,沒有使用Positioned狀況仍是比較好理解的,下面會詳細講解的
  • fit :用來決定沒有Positioned方式時候子Widget的大小,StackFit.loose 指的是子Widget 多大就多大,StackFit.expand使子Widget的大小和父組件同樣大
  • overflow :指子Widget 超出Stack時候如何顯示,默認值是Overflow.clip,子Widget超出Stack會被截斷,Overflow.visible超出部分還會顯示的
Stack(
      children: <Widget>[
        Container(
          height: 300,
          width: 300,
          color: Colors.red,
        ),
        Container(
          height: 200,
          width: 200,
          color: Colors.blue,
        ),
        Container(
          height: 100,
          width: 100,
          color: Colors.yellow,
        )
      ],
    );
複製代碼

IndexedStack

IndexedStack 是 Stack 的子類,Stack 是將全部的子組件疊加顯示,而 IndexedStack 經過 index 只顯示指定索引的子組件,用法以下:

class IndexedStackDemo extends StatefulWidget {
  @override
  _IndexedStackDemoState createState() => _IndexedStackDemoState();
}

class _IndexedStackDemoState extends State<IndexedStackDemo> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(height: 50,),
        _buildIndexedStack(),
        SizedBox(height: 30,),
        _buildRow(),
      ],
    );
  }

  _buildIndexedStack() {
    return IndexedStack(
      index: _index,
      children: <Widget>[
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.red,
            alignment: Alignment.center,
            child: Text('1'),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.green,
            alignment: Alignment.center,
            child: Text('2'),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.yellow,
            alignment: Alignment.center,
            child: Text('3'),
          ),
        ),
      ],
    );
  }

  _buildRow() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        RaisedButton(
          child: Text('1'),
          onPressed: (){
            setState(() {
              _index = 0;
            });
          },
        ),
        RaisedButton(
          child: Text('2'),
          onPressed: (){
            setState(() {
              _index = 1;
            });
          },
        ),
        RaisedButton(
          child: Text('3'),
          onPressed: (){
            setState(() {
              _index = 2;
            });
          },
        ),
      ],
    );
  }
}
複製代碼

六、寬高比(AspectRatio)

AspectRatio 是固定寬高比的組件

Container(
          height: 300,
          width: 300,
          color: Colors.blue,
          alignment: Alignment.center,
          child: AspectRatio(
            aspectRatio: 2 / 1,
            child: Container(color: Colors.red,),
          ),
        )
複製代碼

七、佈局約束

一、FittedBox(縮放佈局)

FittedBox 組件主要作兩件事,縮放(Scale)和位置調整(Position)。

FittedBox 會在本身的尺寸範圍內縮放並調整 child 的位置,使 child 適合其尺寸。FittedBox 和 Android 中的 ImageView 有些相似,將圖片在其範圍內按照規則進行縮放和位置調整。

佈局分爲兩種狀況:

  • 外部有約束的話,按照外部約束調整自身尺寸,而後縮放調整 child ,按照指定條件進行佈局。
  • 沒有外部約束條件,則跟 child 尺寸同樣,指定的縮放和位置屬性將不起做用。
const FittedBox({
    Key key,
    this.fit = BoxFit.contain,
    this.alignment = Alignment.center,
    this.clipBehavior = Clip.hardEdge,
    Widget child,
  })  
複製代碼

這裏有一個新的屬性fit

  • 一、BoxFit.none,沒有任何填充模式
  • 二、BoxFit.fill:不按寬高比例填充,內容不會超過容器範圍
  • 三、BoxFit.contain:按照寬高比等比模式填充,內容不會超過容器範圍
  • 四、BoxFit.cover:按照原始尺寸填充整個容器模式。內容可能回超過容器範圍
  • 五、BoxFit.scaleDown:會根據狀況縮小範圍

Container(
      color: Colors.amberAccent,
      width: 300.0,
      height: 300.0,
      child: FittedBox(
        fit: BoxFit.none,
        alignment: Alignment.topLeft,
          child: new Container(
            color: Colors.red,
            child: new Text("FittedBox"),
          )
      ),
    );
複製代碼

二、FractionallySizedBox

FractionallySizedBox 是一個相對父組件尺寸的組件,用途是基於寬度縮放因子和高度縮放因子來調整佈局大小,大小可能超過父組件位置。

const FractionallySizedBox({
    Key key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget child,
  })
複製代碼
  • 1.widthFactor:FractionallySizedBox組件的寬度因子

    • widthFactor != null時,子組件的寬度等於FractionallySizedBox組件的約束的最大寬度乘以widthFractor
    • widthFractor == null時,FractionallySizedBox組件的寬度約束會原封不動的傳遞給子組件
  • 2.heightFractor: FractionallySizedBox組件的高度因子

    • heightFractor != null時,子組件的高度等於FractionallySizedBox組件的約束的最大高度乘以heightFractor
    • heightFractor == null時,FractionallySizedBox組件的高度約束會原封不動的傳遞給子組件
Container(
      height: 200,
      width: 200,
      color: Colors.blue,
      child: FractionallySizedBox(
        widthFactor: .8,
        heightFactor: .3,
        child: Container(
          color: Colors.red,
        ),
      ),
    )
複製代碼

三、ContainedBox

ContainedBox是一種有約束限制的佈局,在其約定的範圍內,好比最大高度,最小寬度,其子組件是不能逾越的

ConstrainedBox({
    Key key,
    @required this.constraints,
    Widget child,
  })
複製代碼

constraints:添加到child上的額外限制條件,其類型爲BoxConstraints。BoxConstraints的做用是幹啥的呢?其實很簡單,就是限制各類最大最小寬高。說到這裏插一句,double.infinity在widget佈局的時候是合法的,也就說,例如想最大的擴展寬度,能夠將寬度值設爲double.infinity。

八、案例

這個案例來自:flutter.cn/docs/develo…

咱們準備作一下這個界面

具體代碼以下

class demoWidget extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
   return Container(
       height: 300,
       child: Card(
         color: Colors.white,
         margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             topWidget(),
             starWidget(),
             iconWidget()],
         ),
     )
   );
 }
}

class topWidget extends StatelessWidget {
 final mainImage = Container(
   margin: EdgeInsets.fromLTRB(10, 10, 0, 0),
   child: Image.asset(
     'images/pavlova.jpg',
     fit: BoxFit.fill,
     width: 130,
     height: 130,
   ),
 );

 @override
 Widget build(BuildContext context) {
   return Row(
     crossAxisAlignment: CrossAxisAlignment.start,
     children: [
       mainImage,
       Flexible(
           child: rightWidget()
       ),
     ],
   );
 }
}

class rightWidget extends StatelessWidget {
 final titleText = Container(
   padding: EdgeInsets.fromLTRB(10, 15, 0, 0),
   child: Text(
     'Strawberry Pavlova',
     style: TextStyle(
       letterSpacing: 0.5,
       fontSize: 17,
     ),
   ),
 );

 final subTitle = Container(
   padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
   child: Text(
     'Pavlova is a meringue-based dessert named after the Russian ballerina '
         'Anna Pavlova. Pavlova features a crisp crust and soft, light inside, '
         'topped with fruit and whipped cream.',
     style: TextStyle(
       fontSize: 12,
     ),
   ),
 );

 @override
 Widget build(BuildContext context) {
   return Container(
     child: Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [titleText,subTitle],
     ),
   );
 }
}

class starWidget extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Container(
     padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
     child: Row(
       children: [
         Icon(Icons.star, color: Colors.green[500]),
         Icon(Icons.star, color: Colors.green[500]),
         Icon(Icons.star, color: Colors.green[500]),
         Icon(Icons.star, color: Colors.black),
         Icon(Icons.star, color: Colors.black),
       ],
     ),
   );
 }
}

class iconWidget extends StatelessWidget {

 final descTextStyle = TextStyle(
   color: Colors.black,
   fontSize: 18,
   height: 1.2,
 );

 @override
 Widget build(BuildContext context) {
   return Container(
     child: Container(
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceEvenly,
         children: [
           Column(
             children: [
               Icon(Icons.kitchen, color: Colors.green[500]),
               Text('PREP:',style: descTextStyle),
               Text('25 min',style: descTextStyle),
             ],
           ),
           Column(
             children: [
               Icon(Icons.timer, color: Colors.green[500]),
               Text('COOK:',style: descTextStyle),
               Text('1 hr',style: descTextStyle),
             ],
           ),
           Column(
             children: [
               Icon(Icons.restaurant, color: Colors.green[500]),
               Text('FEEDS:',style: descTextStyle),
               Text('4-6',style: descTextStyle),
             ],
           ),
         ],
       ),
     ),
   );
 }
}

複製代碼

代碼地址:github.com/SunshineBro…

相關文章
相關標籤/搜索