常用 Widget 部件介紹及 Flutter 佈局方式

語言: CN / TW / HK

這是我參與11月更文挑戰的第2天,活動詳情檢視:2021最後一次更文挑戰

文字控制元件 Text

``` class TextDemo extends StatelessWidget { final TextStyle _textStyle = TextStyle( fontSize: 16.0, color: Colors.red, );

final String _lector = 'Flutter'; final String _title = 'Dark 語法詳解';

@override Widget build(BuildContext context) { return Text( '$_lector -- $_title:Flutter中文網是中國最大的Flutter開發者交流學習平臺,致力於打造Flutter開發中文社群。在這裡能輕鬆找到程式碼例項、專案案例、並有專人提供最新文件翻譯。', textAlign: TextAlign.center, style: _textStyle, maxLines: 3, overflow: TextOverflow.ellipsis, ); } } ```

image.png

  • TextStyle: 為文字設定字號、顏色、字型樣式等。
  • $變數:可以通過 $變數 的形式對字串進行拼接。
  • textAlign:設定文字居中還是居左或者居右。
  • maxLines:設定文字最大顯示行號。
  • overflow:顯示不完時文字的擷取方式。

可變文字控制元件 RichText

class RichTextDemo extends StatelessWidget { @override Widget build(BuildContext context) { return RichText( text: const TextSpan( text: 'Flutter', style: TextStyle( fontSize: 30, color: Colors.black, ), children: [ TextSpan( text: '中文網', style: TextStyle( fontSize: 16, color: Colors.red, ), ), TextSpan( text: '是中國最大的Flutter開發者交流學習平臺', style: TextStyle( fontSize: 20, color: Colors.blue, ), ), ] ), ); } }

image.png

RichTexttextTextSpan 型別,在 TextSpan 中可以新增 childrenchildren 是一個TextSpan 型別的 List。我們可以在每個 TextSpan 中單獨設定要展示的文字及文字樣式 style。最終展示的時候就是每個 TextSpan 中文字拼接起來的效果。可以做富文字展示。

Container

class ContainerDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.red, child: Row( children: <Widget>[ Container( color: Colors.yellow, child: Icon( Icons.add, size: 45, ), padding: EdgeInsets.all(30), margin: EdgeInsets.all(20), height: 230, ), ], ), ); }

image.png

Container 有點型別我們 iOS 中的 UIView 控制元件,Container 沒設定寬高的情況下,Container 的大小由內部子控制元件撐起。padding 是內邊距,margin 是外邊距。

alignment

const Alignment(this.x, this.y) : assert(x != null), assert(y != null);

Container 有一個重要的屬性 alignmentxy 分別代表子控制元件在當前 Container 中的位置,x-101、分別代表子控制元件居左、居中、居右。y-101、分別代表子控制元件居上、居中、居下。

Flutter 佈局方式

Flutter 的佈局方式中有三個比較重要的子部件,RowColumnStack 分別代表橫向、縱向、多層,分別相當於座標軸的 xyz 軸。

Column

class LayoutColumnDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: Alignment(0.0, 0.0), child: Column( children: [ Container(color: Colors.red, child: Icon(Icons.add, size: 90,)), Container(color: Colors.yellow, child: Icon(Icons.timelapse, size: 60,)), Container(color: Colors.blue, child: Icon(Icons.error, size: 30,)), ], ), ); } }

image.png

Row

class LayoutRowDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: Alignment(1.0, 0.0), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Container(color: Colors.red, child: Icon(Icons.add, size: 90,)), Container(color: Colors.yellow, child: Icon(Icons.timelapse, size: 60,)), Container(color: Colors.blue, child: Icon(Icons.error, size: 30,)), ], ), ); } }

image.png

mainAxisAlignment 代表主軸的開始方向,Row 預設從左往右佈局,當把 mainAxisAlignment 設定為 MainAxisAlignment.end 的時候就是從右向左佈局,代表從結束位置開始。當佈局方式為 Row 的時候,Alignmentx 屬性對水平方向不起作用。

image.png

mainAxisAlignment: MainAxisAlignment.spaceBetween

  • spaceBetween:代表子控制元件在主軸方向排列,剩下的空間平均分佈到子控制元件之間。

image.png

mainAxisAlignment: MainAxisAlignment.spaceAround

  • spaceAround:剩下的空間平均分佈到子控制元件周圍。

image.png

mainAxisAlignment: MainAxisAlignment.spaceEvenly

  • spaceEvenly:剩下的空間在子部件中間及子部件到螢幕邊緣平均分配。

crossAxisAlignment 交叉軸佈局

交叉軸就是主軸的垂直方向,Row 部件的交叉軸就是縱向。相對的其他方向的佈局也是類似。

image.png

crossAxisAlignment: CrossAxisAlignment.start

  • CrossAxisAlignment.start: 點子控制元件在交叉軸方向都從內容頂部開始向下佈局。

image.png

class LayoutRowDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: Alignment(1.0, 0.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ Container(color: Colors.red, child: Text('Hello', style: TextStyle(fontSize: 15))), Container(color: Colors.yellow, child: Text('Flutter', style: TextStyle(fontSize: 30))), Container(color: Colors.blue, child: Text('Demo', style: TextStyle(fontSize: 60))), ], ), ); } }

crossAxisAlignmentCrossAxisAlignment.baseline 的時候必須跟 textBaseline 屬性一起使用,用來設定文字的基準線的對齊方式。

Expanded

class LayoutExpandedDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: Alignment(1.0, 0.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ Expanded(child: Container(color: Colors.red, child: Text('Hello', style: TextStyle(fontSize: 15)))), Expanded(child: Container(color: Colors.yellow, child: Text('Flutter', style: TextStyle(fontSize: 30)))), Expanded(child: Container(color: Colors.blue, child: Text('Demo', style: TextStyle(fontSize: 60)))), ], ), ); } }

image.png

通過上圖可以看到,被 Expanded 包裝的子控制元件會在主軸方向按螢幕的大小等分。當主軸方向為橫向的時候設定子控制元件的寬度就不會起作用。相同,當主軸方向為縱向的時候設定子控制元件的高度就不會起作用。

Stack

class LayoutStackDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: const Alignment(0, 0), child: Stack( children: [ Container(color: Colors.red, width: 200, height: 200, child: Icon(Icons.add)), Container(color: Colors.yellow, width: 100, height: 100, child: Icon(Icons.timelapse)), Container(color: Colors.blue, width: 50, height: 50, child: Icon(Icons.error)), ], ), ); } }

image.png

通過 Stack 佈局,Container 中的子控制元件會由內向外按順序疊加展示。

Positioned

children: [ Positioned(child: Container(color: Colors.red, width: 200, height: 200, child: Icon(Icons.add))), Positioned(child: Container(color: Colors.yellow, width: 100, height: 100, child: Icon(Icons.timelapse)),left: 5,), Positioned(child: Container(color: Colors.blue, width: 50, height: 50, child: Icon(Icons.error)),right: 10,), ],

image.png

當使用 Positioned 的時候,可以設定 left 或者 right 等屬性, left 或者 right 的值為 double 型別,可以設定子部件距離父控制元件的左邊或者右邊的間距。

AspectRatio

class LayoutAspectRatioDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.greenAccent, alignment: const Alignment(0, 0), child: Container( color: Colors.blue, height: 200, child: const AspectRatio(aspectRatio: 1 / 2, child: Icon(Icons.add)) ), ); } }

image.png

Container 可以設定一個 AspectRatio 的子部件來影響當前 Container 控制元件的寬高比,當我們把高度設定為 200 的時候,控制元件的寬度會被自動設定為 100