Flutter 22: 易忽略的【小而巧】的技術點彙總 (二)
小菜繼續整理一些個人不太注意但非常有用的小功能點,可能也是大家熟悉的,只是為了以後使用方便查詢。
1. Opacity 透明度
小菜以前在處理 Widget 的顯隱性時用的是設定 Widget 寬高均為0,方式不太好,偶然間瞭解到 ofollow,noindex"> Opacity ,可以通過處理透明度來處理 Widget 的顯隱性。
Opacity可以使子控制元件透明,可以通過設定 0.0~1.0 之間的值來設定透明度;對於 0.0 子控制元件基本沒有繪製過,對於 1.0 會立即繪製而不實用中間緩衝區。這種方式比直接在 Widget 中新增和刪除子控制元件更有效。
Tips: opacity 的值必須在 0.0~1.0 之間,類似於 Android 中的 Visible 和 inVisible 效果。
Widget childOpacityWid(BuildContext context) { return new Column( children: <Widget>[ new Opacity( opacity: 1.0, child: new Container( height: 80.0, color: Colors.blue, child: new Center(child: new Text('當前 opacity = 1.0')))), new Opacity( opacity: 0.0, child: new Container( height: 80.0, color: Colors.green, child: new Center(child: new Text('當前 opacity = 0.0')))), new Opacity( opacity: 0.5, child: new Container( height: 80.0, color: Colors.redAccent, child: new Center(child: new Text('當前 opacity = 0.5')))) ], ); }

2. Chip 標籤
小菜以前自定義的標籤都是用 Row 配合其他 Widget 來實現的,後來瞭解到 Chip 不僅節省了很多時間,效果也很好。配合 Wrap 流式佈局可以解決很多問題。
const Chip({ Key key, this.avatar,// 左側圖示 @required this.label,// 標籤內容,一般是文字 this.labelStyle,// 標籤樣式 this.labelPadding,// 標籤內邊距 this.deleteIcon,// 刪除圖示,自己配置 this.onDeleted,// 刪除方法,必須呼叫才會顯示刪除圖示 this.deleteIconColor,// 刪除圖示顏色 this.deleteButtonTooltipMessage,// 刪除圖示的提示訊息 this.shape,// 形狀,主要是整個標籤樣式,包括圓角等 this.clipBehavior = Clip.none, this.backgroundColor,// 背景顏色 this.padding,// 整個標籤內邊距 this.materialTapTargetSize,// 刪除圖示點選範圍,可不處理 }) Widget childChipWid(var string, var state) { Widget childChip; if (state == 1) {// 預設圓角 childChip = Chip( label: Text(string, style: new TextStyle(fontSize: 16.0)), deleteIcon: Icon(Icons.clear, color: Colors.black12), labelPadding: EdgeInsets.fromLTRB(6.0, 0.0, 6.0, 0.0), ); } else if (state == 2) {// 設定形狀為圓角矩形 childChip = Chip( label: Text(string, style: new TextStyle(fontSize: 16.0)), deleteIcon: Icon(Icons.clear, color: Colors.black12), labelPadding: EdgeInsets.fromLTRB(2.0, 0.0, 2.0, 0.0), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3.0)), onDeleted: () {}, ); } else {// 新增前置圖示樣式 childChip = Chip( label: Text(string, style: new TextStyle(fontSize: 16.0)), avatar: Icon(Icons.search), deleteIcon: Icon(Icons.clear, color: Colors.black12), labelPadding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), onDeleted: () {}, ); } return childChip; }
Tips:如果要顯示刪除圖示,一定要實現 onDeleted:(){} 方法,否則不顯示。

3. Color 顏色
Color對於每個開發者都很熟悉,對於小菜來說也必須用的屬性, Flutter 提供了很多設定顏色的方式,小菜簡單整理一下。
Colors 方式
Flutter提供了很多便利的色值可以直接使用;大多數色值的顏色從 100 到 900,增量為 100,數字越小,顏色越淺,數字越大,顏色越深。重點樣本(例如redAccent)僅具有值 100/200/400/700。
Colors.redAccent, Colors.red[200], Colors.red, Colors.red[800],
還有一系列具有常見不透明度的黑色和白色。例如: black54 是純黑色,具有 54% 的不透明度。
Colors.black54, Colors.black87,
Color 方式
小菜在做 Android 開發時一般是用 16進位制的色值, Flutter 同樣支援,以 #EE5048 為例:
- ARGB 16進位制方式 : 0x 代表16進位制,進行拆分,第一個引數為透明度;
Color.fromARGB(0xFF, 0xEE, 0x50, 0x48)
- ARGB 10進位制方式 :與16進位制使用相同,只是需要逐個轉成10進位制數;
Color.fromARGB(255, 240, 80, 72)
- RGBO 16進位制方式 :最後一個引數為 0.0~1.0 之間透明度;
Color.fromRGBO(0xEE, 0x50, 0x48, 1.0)
- RGBO 10進位制方式 :與上16進位制使用相同;
Color.fromRGBO(240, 80, 72, 1.0)
- 直接使用16進位制方式 :只需新增 0x 代表16進位制;
Color(0xFFEE5048)
Tips: 0x 後需要設定透明度 FF (完全不透明) 或其他透明度,如果不設定透明度,預設是全透明。

4. Text 文字換行
Text是我們日常一定會用到的 Widget ,根據設定不同的屬性產生不同的樣式效果。小菜主要嘗試了一下換行時的效果。
- softWrap: false
只有一行內容時,若超過設定最大寬度,是否自動換行, true 為換行, false 為不換行; - overflow: TextOverflow.clip 只有一行內容,不換行時,預設截斷超出內容,與設定 clip 屬性效果相同;
- overflow: TextOverflow.fade
只有一行內容,不換行時,將超出的文字淡化為透明;當設定多行顯示時,會將最後一行底部略透明顯示; - overflow: TextOverflow.ellipsis
只有一行內容,不換行時,將超出部分用 ... 代替;當設定超過多行時,最後內容以 ... 顯示。但就目前小菜研究中,無法像 Android 設定 ... 在中間或跑馬燈效果,如果有哪位大神瞭解還請多多指教。
Widget childTextWid(BuildContext context) { return ListView( children: <Widget>[ Container( height: 50.0, color: Colors.green, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容自動換行!Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: true))), Container( height: 50.0, color: Colors.black54, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容不換行!預設自動截斷,Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: false))), Container( height: 50.0, color: Colors.black38, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容不換行!手動設定自動截斷,Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: false, overflow: TextOverflow.clip))), Container( height: 50.0, color: Colors.redAccent, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容不換行!漸變隱藏,Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: false, overflow: TextOverflow.fade))), Container( height: 50.0, color: Colors.blue, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容不換行!省略號樣式,Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: false, overflow: TextOverflow.ellipsis))), Container( color: Colors.blueGrey, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容換行!設定超出超出行數漸變隱藏,Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: true, maxLines: 2, overflow: TextOverflow.fade))), Container( color: Colors.brown, height: 50.0, child: Padding( padding: EdgeInsets.all(5.0), child: Text( 'Text 測試,超過內容換行!設定超出超出行數漸變隱藏,Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?', softWrap: true, maxLines: 2, overflow: TextOverflow.ellipsis))), ], ); }

5. BoxConstraints 佈局約束
小菜在處理圖片時,為了方便適配,藉助 Expanded 均分大小而非固定大小,此時小菜想把圖片擷取中間部分填充滿而不拉伸,採用 Image 的 BoxFit 不能很好的實現,小菜學習了一下 BoxConstraints 佈局約束方式,根據父類佈局的最大最小寬高進行填充。
Widget childBoxImgWid(BuildContext context) { return Column( children: <Widget>[ Expanded( flex: 1, child: ConstrainedBox( child: Image.asset( 'images/icon_hzw01.jpg', fit: BoxFit.cover, ), constraints: new BoxConstraints.expand(), )), Expanded( flex: 1, child: ConstrainedBox( child: Image.asset( 'images/icon_hzw02.jpg', fit: BoxFit.cover, ), constraints: new BoxConstraints.expand(), )), Expanded( flex: 1, child: ConstrainedBox( child: Image.asset( 'images/icon_hzw03.jpg', fit: BoxFit.cover ), constraints: new BoxConstraints.expand(), )), ], ); }

Widget childBoxImgWid(BuildContext context) { return Column( children: <Widget>[ Expanded( flex: 1, child: Image.asset('images/icon_hzw01.jpg', fit: BoxFit.cover)), Expanded( flex: 1, child: Image.asset('images/icon_hzw02.jpg', fit: BoxFit.cover)), Expanded( flex: 1, child: Image.asset('images/icon_hzw03.jpg', fit: BoxFit.cover)) ], ); }

小菜剛接觸 Flutter 時間不長,還有很多不清楚和不理解的地方,如果又不對的地方還希望多多指出。以下是小菜公眾號,歡迎閒來吐槽~

公眾號.jpg