Flutter入門進階之旅(十)Dialog&Toast

謝棟發表於2019-04-15

做原生開發的時候,我們都知道要想讓一個app做的活靈活現,與使用者互動時有更棒的體驗,各種樣式美輪美奐的對話方塊跟提示是必不可少的,Flutter在設計對話方塊的時候充分考慮到了在UI上的體驗,幫助我們設計了一整套的基於material design風格的對話方塊以及輕量級的用於提示的widget。

對話方塊效果圖

看完上面的效果圖,讀者是不是也覺得這一套UI設計給人以很棒的體驗,下面我們就逐一介紹下上圖中出現的常用於提示的widget。

輕量級提示

這裡提到的輕量級提示指的是在提示出現的過程中不會打斷使用者當前正在進行中的操作,只是在UI上有一小段時間的提示,隔一段時間之後提示內容自動消失,例如原生Android的Toast、SnackBar一樣,並不會像Dialog一樣出現之後使用者必須停止正在進行的操作去完成Dialog引發的邏輯操作之後才能繼續在dialog出現之前的操作。

1.Tooltip

Tooltip支援使用者傳入任意一個child作為顯示的Widget,並且在使用者長按Widget時,會在上方或者下方出現類似Toast的提示,隔一段時間自動消失,由於使用起來比較簡單,我就在程式碼註釋裡講解就不展開贅述了。

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Tooltips"),
      ),
      body: Center(
        child: Tooltip(
            message: "顯示提示內容",//提示的內容
            height: 60.0,//Tooltip的高度
            verticalOffset: 50.0,//具體內部child Widget豎直方向的距離,
            preferBelow:false,//是否顯示在下面
            padding: EdgeInsets.all(20.0),//padding
            child: Icon(
              Icons.android,
              size: 50.0,
              color: Colors.green,
            )),
      ),
    );
  }
}

複製程式碼

效果圖

Tooltip

2.SnackBar

SnackBar無論是用法還是功能使用幾乎都跟原生Android一樣 ,唯一有一點需要留意的是在Scaffold.of(context).showSnackBar()中傳遞的context必須不能是Scaffold下面的Context

原因解釋

因為Scaffold.of() 方法需要從Widget樹中去找到Scaffold的Context,所以如果直接在Scaffold中使用showSnackBar,需要在外城包括上Builder Widget,這個Builder不做任何的其他操作,只不過把Widget樹往下移了一層而已,這裡也是很多初學者照著網上的Demo寫完之後怎麼寫彈不出來SnackBar的原因,所以這裡特此說明一下。

來看下SnackBar的效果圖,你會發現跟原生Android如出一轍。

SnackBar

樣例程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(home: new MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("SnackBar"),
      ),
      body: new Center(
        child: new Builder(builder: (BuildContext context) {
          return new RaisedButton(
            onPressed: () {
              //值得注意的是這個context必須不能是Scaffold節點下的context,因為Scaffold.of()
              // 方法需要從Widget樹中去找到Scaffold的Context,所以如果直接在Scaffold中使用showSnackBar,
              // 需要在外城包括上Builder Widget,這個Builder不做任何的其他操作,只不過把Widget樹往下移了一層而已。
              Scaffold.of(context).showSnackBar(new SnackBar(
                content: new Text("SanckBar is Showing "),
                action: new SnackBarAction(
                    label: "撤銷",
                    onPressed: () {
                      print("點選撤回---------------");
                    }),
              ));
            },
            child: new Text("SnackBar提示"),
            color: Colors.cyan,
            highlightColor: Colors.lightBlueAccent,
            disabledColor: Colors.lightBlueAccent,
          );
        }),
      ),
    );
  }
}

//const SnackBar({
//Key key,
//@required this.content,//內容
//this.backgroundColor,//背景
//this.action,//其他操作
//this.duration: _kSnackBarDisplayDuration,//顯示時長
//this.animation,//進出動畫
//})

複製程式碼

非輕量級操作

上面介紹了Tooltip跟SnackBar,在介紹此二者的時候筆者也提到它們定位為輕量級的提示Widget,那對應的就會有非輕量級的提示元件,意思就是在此類提示出現的過程中,會打斷使用者正在進行的操作,強制使用者處處理對話方塊上的邏輯之後才能回過頭來繼續原有的使用者操作,例如AlertDialog、BottomSheetDialog等,接下來筆者就帶大家一起體驗一下這類提示操作的用法。

Flutter中要求開發者通過showDialog(context,child),來喚起各種不同型別的dialog顯示,context為上下文引數,child為要顯示的對話方塊型別,例如,SimpleDialog、AlertDialog、AboutDialog、BottomSheetDialog等都需要藉助showDialog來喚起。

1.SimpleDialog

SimpleDialog跟它的名字一樣,它就是一個簡單的對話方塊,開發者只需傳入title跟child就可以使用它,其中child是一個Widget陣列,使用者可以根據業務需求傳入任意的Widget,然後藉助showDialog喚起即可。

效果圖

simpleDailog

樣例程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(home: new MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("SimpleDialog"),
      ),
      body: new Center(
        child:  new RaisedButton(
              onPressed: () {
                showDialog(
                    context: context,
                    child: new SimpleDialog(
                      title: new Text("標題"),
                      contentPadding: const EdgeInsets.all(10.0),
                      children: <Widget>[    //SimpleDialog內可指定多個children
                        new Text("文字內容1"),
                        new ListTile(
                          leading: new Icon(Icons.android),
                          title: new Text("android"),
                        ),

                        new Text("文字內容2"),
                        new Text("文字內容3"),
                        new Text("文字內容4"),
                      ],
                    ));
              },
              child: new Text("Dialog出來"),
              color: Colors.blue,
              highlightColor: Colors.lightBlueAccent,
              disabledColor: Colors.lightBlueAccent),

      ),
    );
  }
}

複製程式碼

2.AlertDialog

AlertDialog其實就是simpleDialog的封裝,更加方便開發者使用,只不過在SimpleDialog的基礎上新增了action操作而已,使用者可以定製具體類似,“取消”、“確定”等一切可能存在dialog上的邏輯處理。其餘沒有什麼需要特別強調的知識點,也是跟simpledialog一樣,需要藉助showDialog喚起,使用起來比較簡單,直接從程式碼裡說明了。

樣例程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(home: new MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("AlertDialog"),
      ),
      body: new Center(
        child: new Builder(builder: (BuildContext context) {
          return new RaisedButton(
            onPressed: () {
              showDialog(
                  context: context,
                  child: new AlertDialog(
                    title: new Text("標題"),
                    content: new Text("內容區域"),
                    actions: <Widget>[
                      new FlatButton(
                          onPressed: () {
                            Navigator.of(context);
                          },
                          child: new Text("確定")),
                      new FlatButton(
                          onPressed: () {
                            print("點選取消------");
                          },
                          child: new Text("取消")),
                    ],
                  ));
            },
            color: Colors.lightBlueAccent,
            child: new Icon(Icons.phone),
          );
        }),
      ),
    );
  }
}

複製程式碼

效果圖

alertdialog

文章開頭的效果圖上提到的aboutDialog跟alertDialog類似,同樣也是封裝了simpleDialog,讀者可自行閱讀嘗試具體用法,我就不在此詳細解說了,下面我想說一下BottomSheetDialog跟ModalBottomSheetDialog。

3.BottomSheetDialog、ModalBottomSheetDialog

BottomSheetDialog、ModalBottomSheetDialog同樣也是需要藉助showDialog喚起,就跟它名字一樣,這兩種dialog是從螢幕下方向上彈出的,不同的是BottomSheetDialog預設會鋪滿全屏顯示,而ModalBottomSheetDialog半屏顯示,二者都支援隨使用者手指拖動上下移動。

方法簽名

1.showBottomSheet(context,child) 上下文引數,Widget陣列 2.showModalBottomSheet(context,child) 上下文引數,Widget陣列

來一起體驗一下這倆東西怎麼使用

BottomSheetDialog

樣例程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(home: new MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("BottomSheet"),
      ),
      body: new Column(
        children: <Widget>[
          new Builder(builder: (BuildContext context){
            return new RaisedButton(
              onPressed: () {
                showBottomSheet(
                    context: context,
                    builder: (BuildContext context) {
                      return new Container(
                        child: new Padding(
                          padding: const EdgeInsets.all(10.0),
                          child: new Column(
                            children: <Widget>[
                              new ListTile(
                                leading: new Icon(Icons.chat),
                                title: new Text("對話方塊列表1"),
                              ),
                              new ListTile(
                                leading: new Icon(Icons.help),
                                title: new Text("對話方塊列表2"),
                              ),
                              new ListTile(
                                leading: new Icon(Icons.settings),
                                title: new Text("對話方塊列表3"),
                              ),
                              new ListTile(
                                leading: new Icon(Icons.more),
                                title: new Text("對話方塊列表4"),
                              ),
                            ],
                          ),
                        ),
                      );
                    });
              },
              child: new Text("BottomSheet"),
            );
          }),


          //showModalBottomSheet與BottomSheet的區別是 BottomSheet充滿螢幕,ModalBottomSheet半屏
          new RaisedButton(
            onPressed: () {
              showModalBottomSheet(
                  context: context,
                  builder: (BuildContext context) {
                    return new Container(
                      child: new Padding(
                        padding: const EdgeInsets.all(10.0),
                        child: new Column(
                          children: <Widget>[
                            new ListTile(
                              leading: new Icon(Icons.chat),
                              title: new Text("對話方塊列表1"),
                            ),
                            new ListTile(
                              leading: new Icon(Icons.help),
                              title: new Text("對話方塊列表2"),
                            ),
                            new ListTile(
                              leading: new Icon(Icons.settings),
                              title: new Text("對話方塊列表3"),
                            ),
                            new ListTile(
                              leading: new Icon(Icons.more),
                              title: new Text("對話方塊列表4"),
                            ),
                          ],
                        ),
                      ),
                    );
                  });
            },
            child: new Text("ModalBottomSheet"),
          ),
        ],
      ),
    );
  }
}
複製程式碼

相關文章