Flutter - 自定義Dialog(2019.07.08更新)

Flutter - 自定義Dialog

開(kāi)發(fā)中,我們經(jīng)常需要向用戶展示信息,多數(shù)情況下,我們使用dialog展示提示信息,那么在Flutter中如何創(chuàng)建dialog, 并使用呢?現(xiàn)在就讓我們來(lái)看看如何打造我們自己的dialog對(duì)象。

So Easy!

Dialog對(duì)象,我們需要重寫build函數(shù)

自定義Dialog對(duì)象,需要繼承Dialog類,盡管Dialog提供了child參數(shù)供寫視圖界面,但是往往會(huì)達(dá)不到我們想要的效果,因?yàn)槟J(rèn)的Dialog背景框是滿屏的。。。那么我們就需要完全定義界面了,就需要重寫build函數(shù)。下面我們編寫一個(gè)加載對(duì)話框,如圖示:

加載對(duì)話框

如圖,我們需要打造一個(gè)類似的對(duì)話框,應(yīng)該具體實(shí)現(xiàn)呢?首先,繼承Dialog

import 'package:flutter/material.dart';

// ignore: must_be_immutable
class LoadingDialog extends Dialog {
  String text;

  LoadingDialog({Key key, @required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Material( //創(chuàng)建透明層
      type: MaterialType.transparency, //透明類型
      child: new Center( //保證控件居中效果
        child: new SizedBox(
          width: 120.0,
          height: 120.0,
          child: new Container(
            decoration: ShapeDecoration(
              color: Color(0xffffffff),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(
                  Radius.circular(8.0),
                ),
              ),
            ),
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                new CircularProgressIndicator(),
                new Padding(
                  padding: const EdgeInsets.only(
                    top: 20.0,
                  ),
                  child: new Text(
                    text,
                    style: new TextStyle(fontSize: 12.0),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

上面我們已經(jīng)創(chuàng)建了一個(gè)加載對(duì)話框,那么我們?cè)撊绾握故具@個(gè)dialog呢?showDialog函數(shù)

showDialog<Null>(
    context: context, //BuildContext對(duì)象
    barrierDismissible: false,
    builder: (BuildContext context) {
        return new LoadingDialog( //調(diào)用對(duì)話框
            text: '正在獲取詳情...',
        );
    });

對(duì)話框展示后,我們還需要關(guān)閉呀。關(guān)閉其實(shí)就很簡(jiǎn)單了!

Navigator.pop(context); //關(guān)閉對(duì)話框
不要著急,聽(tīng)我說(shuō)完嘛

再來(lái)個(gè)栗子,看客請(qǐng)注意

// ignore: must_be_immutable
class MessageDialog extends Dialog {
  String title;
  String message;
  String negativeText;
  String positiveText;
  Function onCloseEvent;
  Function onPositivePressEvent;

  MessageDialog({
    Key key,
    @required this.title,
    @required this.message,
    this.negativeText,
    this.positiveText,
    this.onPositivePressEvent,
    @required this.onCloseEvent,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: const EdgeInsets.all(15.0),
      child: new Material(
        type: MaterialType.transparency,
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Container(
              decoration: ShapeDecoration(
                color: Color(0xffffffff),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(8.0),
                  ),
                ),
              ),
              margin: const EdgeInsets.all(12.0),
              child: new Column(
                children: <Widget>[
                  new Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: new Stack(
                      alignment: AlignmentDirectional.centerEnd,
                      children: <Widget>[
                        new Center(
                          child: new Text(
                            title,
                            style: new TextStyle(
                              fontSize: 19.0,
                            ),
                          ),
                        ),
                        new GestureDetector(
                          onTap: this.onCloseEvent,
                          child: new Padding(
                            padding: const EdgeInsets.all(5.0),
                            child: new Icon(
                              Icons.close,
                              color: Color(0xffe0e0e0),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  new Container(
                    color: Color(0xffe0e0e0),
                    height: 1.0,
                  ),
                  new Container(
                    constraints: BoxConstraints(minHeight: 180.0),
                    child: new Padding(
                      padding: const EdgeInsets.all(12.0),
                      child: new IntrinsicHeight(
                        child: new Text(
                          message,
                          style: TextStyle(fontSize: 16.0),
                        ),
                      ),
                    ),
                  ),
                  this._buildBottomButtonGroup(),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildBottomButtonGroup() {
    var widgets = <Widget>[];
    if (negativeText != null && negativeText.isNotEmpty) widgets.add(_buildBottomCancelButton());
    if (positiveText != null && positiveText.isNotEmpty) widgets.add(_buildBottomPositiveButton());
    return new Flex(
      direction: Axis.horizontal,
      children: widgets,
    );
  }

  Widget _buildBottomCancelButton() {
    return new Flexible(
      fit: FlexFit.tight,
      child: new FlatButton(
        onPressed: onCloseEvent,
        child: new Text(
          negativeText,
          style: TextStyle(
            fontSize: 16.0,
          ),
        ),
      ),
    );
  }

  Widget _buildBottomPositiveButton() {
    return new Flexible(
      fit: FlexFit.tight,
      child: new FlatButton(
        onPressed: onPositivePressEvent,
        child: new Text(
          positiveText,
          style: TextStyle(
            color: Color(Colors.teal.value),
            fontSize: 16.0,
          ),
        ),
      ),
    );
  }
}

效果圖:

消息對(duì)話框

通過(guò)查看評(píng)論,評(píng)論里有朋友說(shuō)對(duì)話框不支持透明區(qū)域的點(diǎn)擊

  • 邏輯:通過(guò) ** Stack ** 疊加一個(gè) ** GestureDetector ** 布局,添加一個(gè)點(diǎn)擊事件即可。這個(gè)方法是一個(gè)網(wǎng)友告訴我的,之前我也很頭疼這個(gè),感謝!

  • 查看源碼:

    WillPopScope(
        onWillPop: () {
          _onNavigationClickEvent();
          return Future.value(false);
        },
        child: Material(
          type: MaterialType.transparency,
          child: Stack(
            fit: StackFit.expand,
            children: <Widget>[
              GestureDetector(onTap: _onNavigationClickEvent),
              _buildContentView(), //構(gòu)建具體的對(duì)話框布局內(nèi)容
            ],
          ),
        ),
      )
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容