1. 程式人生 > >Flutter 27: 易忽略的【小而巧】的技術點彙總 (四)

Flutter 27: 易忽略的【小而巧】的技術點彙總 (四)

      小菜繼續整理 Flutter 中日常用到的小知識點。

1. CachedNetworkImage 快取圖片

      對於載入網路圖片時,新增一個載入動畫或網路圖片異常時新增一個錯誤圖片會給使用者一個良好的體驗,此時 CachedNetworkImage 可以幫我們解決這個問題。CachedNetworkImage 是一個三方 pub 庫,引入的基本方式省略;

      CachedNetworkImage

中有兩個屬性很重要:

  1. placeholder 用來在載入圖片時的緩衝過程,可以是動態 loading 亦或者 Widget 等;
  2. errorWidget 用來網路圖片載入異常時展現,可自定義進行展示。

      Tips: 在使用載入 loading 或預設圖片時,建議限制 loading 和預設圖片的大小,這樣不會出現預設圖片比載入網路圖更大的效果。

Widget _cachedNetImgWid() {
  return Container(
      color: Colors.grey,
      child: Center(
          child: CachedNetworkImage(
        height: 300.0,
        placeholder: Container(
            width: 50.0, height: 50.0, child: CircularProgressIndicator()),
        errorWidget: Container(
            height: 300.0, child: Image.asset('images/icon_wrong.jpg')),
        imageUrl:
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1544938569112&di=feeab11968f3870520482630563c4f54&imgtype=0&src=http%3A%2F%2Fi1.hdslb.com%2Fbfs%2Farchive%2Fac5c906111130579c6909aae47f6656e20d0906b.jpg',
      )));
}

2. TextInputAction 鍵盤底部按鈕

      小菜在使用 TextField 文字框時會對鍵盤進行操作,為了良好對使用者體驗。在鍵盤右下角會有不同的按鈕樣式。例如搜尋頁面在輸入完成搜尋資訊後展示搜尋的按鈕更便捷。此時需要考慮 TextInputAction 屬性,可自定義展示內容。Flutter 提供了13種狀態,但需注意的是有些是區分 AndroidiOS 的,使用時需加註意。

Widget _textFiledWid() {
  return Padding(padding: EdgeInsets.all(10.0),child:ListView(children: <Widget>[
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-done')),
    TextField(textInputAction: TextInputAction.done),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-go')),
    TextField(textInputAction: TextInputAction.go),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-newline')),
    TextField(textInputAction: TextInputAction.newline),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-next')),
    TextField(textInputAction: TextInputAction.next),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-search')),
    TextField(textInputAction: TextInputAction.search),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-send')),
    TextField(textInputAction: TextInputAction.send),
    Padding(padding: EdgeInsets.all(8.0),child:Text('鍵盤右下角按鈕-join')),
    TextField(textInputAction: TextInputAction.join),
  ]));
}

3. DefaultTextStyle 預設文字樣式

      小菜在學習過程中發現一個很方便的 DefaultTextStyle,用來處理當前頁面統一的文字樣式。與 Android 中對文字進行自定義 style 很相似。

      在當前頁面中設定統一的 DefaultTextStyle 預設文字樣式,在當前頁面中用到的 Text 預設應用的都是該樣式,若需要調整部分樣式,直接設定 TextStyle 即可;若不需要重用該樣式,設定 inherit: false 屬性即可,但 textAlign 並不在該效果內。

Widget _childDefaultTextWid() {
  return new SafeArea(
      top: false,
      child: Scaffold(
          appBar: new AppBar(
            title: Text('DefaultTextStyle Demo'),
          ),
          body: DefaultTextStyle(
            style: TextStyle(
                color: Colors.blueGrey, wordSpacing: 10.0, fontSize: 20.0),
            textAlign: TextAlign.center,
            child: Container(
                child: ListView(children: <Widget>[
              Text("Ha ha ha!預設文字樣式(局中/20.0)"),
              Text("Ha ha ha!與預設文字樣式部分不同",
                  style: TextStyle(color: Colors.redAccent),
                  textAlign: TextAlign.left),
              Text("Ha ha ha!", style: TextStyle(inherit: false)),
              Text("Ha ha ha!自己單獨樣式",
                  style: TextStyle(inherit: false, color: Colors.grey))
            ])),
          )));
}

4. ExpansionTile 擴充套件Tile

      小菜在學習過程中嘗試了一下 ExpansionTile,是一個可向下擴充套件空間的 Widget,如效果圖。

const ExpansionTile({
    Key key,
    this.leading,           // 前置圖示
    @required this.title,   // 標題內容
    this.backgroundColor,   // 背景色包括擴充套件空間整體背景色
    this.onExpansionChanged,// 擴充套件時監聽狀態
    this.children = const <Widget>[],   // 擴充套件空間
    this.trailing,          // 動畫效果
    this.initiallyExpanded = false,     // 初始化時是否展開
}) : assert(initiallyExpanded != null),
       super(key: key);

      小菜嘗試過程中發現 ExpansionTile 雖然很方便,效果也很好,但是也有一些侷限性,如下:

  1. 預設右側箭頭圖示是固定的,包括動畫旋轉角度等,不能直接調整,需要自定義;
  2. 點選擴充套件區域不會消失,需要自定義。

Widget _childExpanTileWid() {
  return new SafeArea(
      child: Scaffold(
          appBar: AppBar(title: Text('擴充套件 Tile')),
          body: Container(
              child: ExpansionTile(
                  title: Text('大禮包'),
                  leading: Icon(Icons.adjust),
                  backgroundColor: Colors.grey,
                  onExpansionChanged: (bool) {
                    _exState = bool;
                  },
                  children: <Widget>[
                Container(
                    decoration: BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: Colors.white),
                    margin: EdgeInsets.all(5.0),
                    child: Column(children: <Widget>[
                      Row(children: <Widget>[
                        Padding(
                            padding: EdgeInsets.fromLTRB(10.0, 8.0, 0.0, 8.0),
                            child: Text('1. 可獲取雙倍會員積分;',
                                style: TextStyle(color: Colors.blue, fontSize: 16.0)))
                      ]),
                      Row(children: <Widget>[
                        Padding(
                            padding: EdgeInsets.fromLTRB(10.0, 8.0, 0.0, 8.0),
                            child: Text('2. 積分兌換獎品8折優惠;',
                                style: TextStyle(color: Colors.blue, fontSize: 16.0)))
                      ])
                    ]))
              ]))));
}

5. Spacer 佔位

      Spacer 是小菜偶然間瞭解到的一個很強大的 WidgetSpacer 小菜的理解是佔位元件,直接看效果圖更加直觀。Spacer 建立一個可調節的空間隔,可用於調整 Flex 容器(如行或列)中視窗小部件之間的間距;預設 flex: 1

Widget _childSpacerWid() {
  return new SafeArea(
      top: false,
      child: Scaffold(
          appBar: new AppBar(
            title: Text('Spacer Demo'),
          ),
          body: Column(children: <Widget>[
            Row(children: <Widget>[
              Text('Begin', style: TextStyle(color: Colors.redAccent)),
              Spacer(),
              Text('Middle', style: TextStyle(color: Colors.greenAccent)),
              Spacer(flex: 2),
              Text('End', style: TextStyle(color: Colors.blue))
            ]),
            Row(children: <Widget>[
              Text('Begin', style: TextStyle(color: Colors.redAccent)),
              Spacer(),
              Text('Middle', style: TextStyle(color: Colors.greenAccent)),
              Text('End', style: TextStyle(color: Colors.blue))
            ]),
            Row(children: <Widget>[
              Text('Begin', style: TextStyle(color: Colors.redAccent)),
              Text('Middle', style: TextStyle(color: Colors.greenAccent)),
              Spacer(flex: 2),
              Text('End', style: TextStyle(color: Colors.blue))
            ])
          ])));
}

      如果有不對的地方還希望多多指出。