我们平时在做一个项目时,肯定会有许多需要显示弹窗的地方。弹窗的样式由UI给出,不用地方有不同的弹窗。想着可以把一些常用的弹窗封装成一个工具类,使用时只需替换不同元素(一般就是文本内容)即可。

 

话不多说,先上示例效果图:

底部单按钮普通提示弹出框:

底部两按钮普通提示弹出框:

底部弹出列表单项选择弹出框:

使用代码

// 底部单按钮普通提示弹出框
RaisedButton(
  child: Text('使用DialogUtil底部单按钮普通提示弹出框'),
  onPressed: () {
    DialogUtil(
        context: context,
        onBtnPressed: () {
          Navigator.pop(context);
        }).showNoticeDialogWithOneButton();
  },
),

// 底部两按钮普通提示弹出框
RaisedButton(
  child: Text('使用DialogUtil底部两按钮普通提示弹出框'),
  onPressed: () {
    DialogUtil(
        context: context,
        content: '这是底部两按钮普通提示弹出框。确认继续么?',
        onLeftBtnPressed: () {
           Navigator.pop(context);
        },
        onRightBtnPressed: () {
          // 确认后要做的的事
          Navigator.pop(context);
        }).showNoticeDialogWithTwoButtons();
  },
),

// 底部弹出列表单项选择弹出框
RaisedButton(
  child: Text('使用DialogUtil底部弹出列表单项选择弹出框'),
  onPressed: () {
    DialogUtil(
        context: context,
        title: '取消原因',
        itemStringList: _cancelReasonList,
        selectIndex: selectIndex,
        onSelected: _handleCancelReasonSelected,
        ).showSheetView();
  },
),

DialogUtil完整代码

import 'package:flutter/material.dart';

/// FileName dialog_util
///
/// @Author wangpenghui
/// @Date 2022/3/2 16:13
///
/// @Description 显示弹窗dialog工具类
class DialogUtil {
  final BuildContext context;

  /// 标题
  final String title;

  /// 内容
  final String content;

  /// 按钮名称
  final String btnName;

  /// 按钮字体颜色
  final Color btnColor;

  /// 左侧按钮名称
  final String leftBtnName;

  /// 左侧按钮字体颜色
  final Color leftBtnColor;

  /// 右侧按钮名称
  final String rightBtnName;

  /// 右侧按钮字体颜色
  final Color rightBtnColor;

  /// 点击背景是否可以关闭弹窗
  final bool barrierDismissible;

  /// 点击返回按钮是否可以关闭弹窗
  final bool backDismissible;

  /// 背景颜色
  final Color barrierColor;

  /// 阴影
  final double elevation;

  /// 内边距
  final EdgeInsets padding;

  /// 按钮点击回调
  Function onBtnPressed;

  /// 左侧按钮点击回调
  Function onLeftBtnPressed;

  /// 右侧按钮点击回调
  Function onRightBtnPressed;

  /// 弹窗列表
  final List<String> itemStringList;

  /// 选中的索引,默认选中第一个
  int selectIndex = 0;

  /// 选择item后回调
  final ValueChanged<int> onSelected;

  DialogUtil(
      {@required this.context,
      this.title = '提示',
      this.content = '这是底部单按钮普通提示弹出框,请知晓',
      this.btnName = '知道了',
      this.btnColor = const Color(0xFFFF8900),
      this.leftBtnName = '取消',
      this.leftBtnColor = const Color(0xFF666666),
      this.rightBtnName = '确认',
      this.rightBtnColor = const Color(0xFFFE3826),
      this.onBtnPressed,
      this.onLeftBtnPressed,
      this.onRightBtnPressed,
      this.barrierColor = Colors.black54,
      this.barrierDismissible = true,
      this.backDismissible = true,
      this.elevation = 0,
      this.padding,
      this.itemStringList,
      this.selectIndex,
      this.onSelected});

  void showNoticeDialogWithOneButton() {
    _showGeneralDialog(builder: (BuildContext context) {
      return WillPopScope(
        child: AnimatedPadding(
          padding: padding == null
              ? EdgeInsets.symmetric(horizontal: 32, vertical: 24)
              : padding,
          duration: Duration(milliseconds: 100),
          curve: Curves.decelerate,
          child: MediaQuery.removeViewInsets(
            removeLeft: true,
            removeTop: true,
            removeRight: true,
            removeBottom: true,
            context: context,
            child: Center(
              child: Material(
                elevation: elevation,
                borderRadius: BorderRadius.circular(14),
                child: _noticeViewWithOneButton(),
              ),
            ),
          ),
        ),
      );
    });
  }

  void showNoticeDialogWithTwoButtons() {
    _showGeneralDialog(builder: (BuildContext context) {
      return WillPopScope(
        child: AnimatedPadding(
          padding: padding == null
              ? EdgeInsets.symmetric(horizontal: 32, vertical: 24)
              : padding,
          duration: Duration(milliseconds: 100),
          curve: Curves.decelerate,
          child: MediaQuery.removeViewInsets(
            removeLeft: true,
            removeTop: true,
            removeRight: true,
            removeBottom: true,
            context: context,
            child: Center(
              child: Material(
                elevation: elevation,
                borderRadius: BorderRadius.circular(14),
                child: _noticeViewWithTwoButtons(),
              ),
            ),
          ),
        ),
      );
    });
  }

  /// 重写showGeneralDialog,系统自带的背景背景透明不能修改
  void _showGeneralDialog({
    Widget Function(BuildContext) builder,
    Widget child,
  }) {
    showGeneralDialog(
      context: context,
      pageBuilder: (BuildContext buildContext, Animation<double> animation,
          Animation<double> secondaryAnimation) {
        final Widget pageChild = child ?? Builder(builder: builder);
        return SafeArea(
          child: Builder(builder: (BuildContext context) {
            return pageChild;
          }),
        );
      },
      barrierDismissible: barrierDismissible,
      barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
      barrierColor: barrierColor,
      transitionDuration: const Duration(milliseconds: 150),
      transitionBuilder: (BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation, Widget child) {
        return FadeTransition(
          opacity: CurvedAnimation(
            parent: animation,
            curve: Curves.easeOut,
          ),
          child: child,
        );
      },
    );
  }

  Widget _noticeViewWithOneButton() {
    return Container(
      constraints: BoxConstraints(
        minHeight: 130,
      ),
      width: double.infinity - 104,
      child: Column(
        mainAxisSize: MainAxisSize.min, //column自适应子控件的高度,不加这条默认会撑到最大
        children: <Widget>[
          _contentViewInOneButton(),
          Divider(
            height: 1,
            thickness: 1,
            color: Color(0xFFEEEEEE),
          ),
          _bottomViewInOneButton(),
        ],
      ),
    );
  }

  Widget _noticeViewWithTwoButtons() {
    return Container(
      constraints: BoxConstraints(
        minHeight: 140,
      ),
      width: double.infinity - 104,
      child: Column(
        mainAxisSize: MainAxisSize.min, //column自适应子控件的高度,不加这条默认会撑到最大
        children: <Widget>[
          _titleViewInTwoButtons(),
          _contentViewInTwoButtons(),
          Divider(
            height: 1,
            thickness: 1,
            color: Color(0xFFEEEEEE),
          ),
          _bottomViewInTwoButtons(),
        ],
      ),
    );
  }

  Widget _titleViewInTwoButtons() {
    return Container(
      margin: EdgeInsets.only(top: 19, left: 16, right: 16),
      height: 22,
      child: Text(title,
          style: TextStyle(
            color: Color(0xFF333333),
            fontSize: 17,
            fontWeight: FontWeight.w400,
          )),
    );
  }

  Widget _contentViewInTwoButtons() {
    return Container(
      constraints: BoxConstraints(minHeight: 32),
      margin: EdgeInsets.only(top: 9, bottom: 14, left: 16, right: 16),
      child: Text(content,
          textAlign: TextAlign.center,
          style: TextStyle(
              color: Color(0xFF666666),
              fontSize: 12,
              fontWeight: FontWeight.w400)),
    );
  }

  Widget _bottomViewInTwoButtons() {
    return Container(
      height: 43,
      child: Row(
        children: <Widget>[
          _clickView(leftBtnName, leftBtnColor, onLeftBtnPressed),
          VerticalDivider(
            color: Color(0xFFEEEEEE),
            width: 1,
            thickness: 1,
          ),
          _clickView(rightBtnName, rightBtnColor, onRightBtnPressed),
        ],
      ),
    );
  }

  Widget _contentViewInOneButton() {
    return Container(
      constraints: BoxConstraints(minHeight: 44),
      margin: EdgeInsets.only(top: 22, bottom: 20, left: 16, right: 16),
      alignment: Alignment.center,
      child: Text(content,
          textAlign: TextAlign.center,
          style: TextStyle(
              color: Color(0xFF333333),
              fontSize: 17,
              fontWeight: FontWeight.w400)),
    );
  }

  Widget _bottomViewInOneButton() {
    return Container(
      height: 43,
      child: Row(
        children: <Widget>[
          _clickView(btnName, btnColor, onBtnPressed),
        ],
      ),
    );
  }

  Widget _clickView(String btnName, Color textColor, Function btnClick) {
    return Expanded(
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: btnClick,
        child: Container(
          height: 43,
          alignment: Alignment.center,
          child: Text(btnName,
              style: TextStyle(
                  color: textColor,
                  fontSize: 17,
                  fontWeight: FontWeight.w400)),
        ),
      ),
    );
  }

  void showSheetView() {
    showModalBottomSheet(
        context: context,
        isScrollControlled: true,
        backgroundColor: Color(0x33000000),
        builder: (context) {
          return StatefulBuilder(
            builder: (context, _setState) {
              return Column(
                children: <Widget>[
                  Expanded(
                    child: GestureDetector(
                      onTap: () {
                        onSelected(selectIndex);
                        Navigator.pop(context);
                      },
                    ),
                  ),
                  Container(
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.only(
                          topLeft: Radius.circular(12),
                          topRight: Radius.circular(12)),
                      color: Color(0xFFF7F7F7),
                    ),
                    child: Column(
                      children: <Widget>[
                        Column(
                          children: <Widget>[
                            Container(
                              width: double.infinity,
                              padding: EdgeInsets.only(
                                  top: 14, left: 20, right: 20),
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.only(
                                    topLeft: Radius.circular(12),
                                    topRight: Radius.circular(12)),
                                color: Colors.white,
                              ),
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: <Widget>[
                                  Text(
                                    title,
                                    style: TextStyle(
                                      fontSize: 17,
                                      color: Color(0xFF333333),
                                      fontWeight: FontWeight.w500,
                                    ),
                                  ),
                                  Container(
                                    width: double.infinity,
                                    padding: EdgeInsets.only(
                                        top: 14, bottom: 14),
                                    child: Column(
                                      children: _chooseListAllWidget(_setState),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),
                        Container(
                          margin: EdgeInsets.only(top: 6),
                          child: GestureDetector(
                            child: Container(
                              height: 56,
                              width: double.infinity,
                              alignment: Alignment.center,
                              color: Colors.white,
                              child: Text(
                                '取消',
                                style: TextStyle(
                                  fontSize: 17,
                                  color: Color(0xFF333333),
                                  fontWeight: FontWeight.w400,
                                ),
                              ),
                            ),
                            onTap: () {
                              onSelected(selectIndex);
                              Navigator.pop(context);
                            },
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              );
            },
          );
        });
  }

  List<Widget> _chooseListAllWidget(StateSetter setState) {
    List<Widget> widgetList = [];
    for (int i = 0; i < itemStringList.length; i++) {
      widgetList.add(_chooseListItemWidget(i, setState));
    }
    return widgetList;
  }

  Widget _chooseListItemWidget(int index, StateSetter setMyState) {
    return GestureDetector(
      child: Container(
        padding: EdgeInsets.only(top: 11, bottom: 11),
        child: Row(
          children: <Widget>[
            Expanded(
              child: Text(
                itemStringList[index],
                style: TextStyle(
                  fontSize: 15,
                  color: Color(0xFF333333),
                  fontWeight: FontWeight.w400,
                ),
              ),
            ),
            Image.asset(
              selectIndex == index
                  ? 'images/img/icon_checked.webp'
                  : 'images/img/icon_unchecked.webp',
              width: 16.5,
              height: 16.5,
            ),
          ],
        ),
      ),
      onTap: () {
        setMyState(() {
          selectIndex = index;
          onSelected(selectIndex);
        });
        Navigator.pop(context);
      },
    );
  }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐