flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果

这篇具有很好参考价值的文章主要介绍了flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果

在开发过程中,经常使用到提示框Dialog,与sheet,使用到了flutter的showDialog与showModalBottomSheet
我这里类似alert弹窗直接调用 flutter 中提供的showDialog()函数显示对话框。
我这里类似Sheet底部弹窗调用 flutter 中提供的showModalBottomSheet从屏幕下方弹出一个对话框。

效果图如下

flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果,flutter开发实战,flutter,移动开发,flutter,showDialog,Sheet,Alert

flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果,flutter开发实战,flutter,移动开发,flutter,showDialog,Sheet,Alert

一、定义dialog内容

定义dialog内容,实现标题、内容描述、按钮操作等功能。

class DialogItem {
  String? title;
  String? color;

  DialogItem({this.title, this.color});
}

class ShowAlertDialog extends StatefulWidget {
  const ShowAlertDialog({
    Key? key,
    this.contentAlign = TextAlign.left,
    required this.onTap,
    this.itemTitles,
    this.content,
    this.title,
    this.children,
  }) : super(key: key);

  // 内容区域布局
  final TextAlign contentAlign;

  final String? title;

  final String? content;

  // 点击返回index 0 1
  final Function onTap;

  //按钮
  final List<DialogItem>? itemTitles;

  final List<Widget>? children;

  
  State<ShowAlertDialog> createState() => _ShowAlertDialogState();
}

class _ShowAlertDialogState extends State<ShowAlertDialog> {
  
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      child: Center(
        // ClipRRect 创建圆角矩形 要不然发现下边button不是圆角
        child: ClipRRect(
          borderRadius: BorderRadius.circular(4.0),
          child: Container(
            color: Color(0xFFFFFFFF),
            width: 300,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                SizedBox(
                  height: 25.0,
                ),
                _buildTitleWidget(),
                SizedBox(
                  height: (_hasTitleAndContent() ? 10.0 : 0.0),
                ),
                _buildContentWidget(),
                SizedBox(height: 25),
                Container(
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: Color(0xFFf5f5f5),
                        width: 1,
                      ),
                    ),
                  ),
                ),
                _buildItemWidget(),
              ],
            ),
          ),
        ),
      ),
    );
  }

  bool _hasTitle() {
    if (widget.title != null && widget.title!.isNotEmpty) {
      return true;
    }

    return false;
  }

  bool _hasContent() {
    if (widget.content != null && widget.content!.isNotEmpty) {
      return true;
    }

    return false;
  }

  bool _hasTitleAndContent() {
    if (_hasTitle() && _hasContent()) {
      return true;
    }
    return false;
  }

  Widget _buildTitleWidget() {
    bool aHasTitle = _hasTitle();
    if (aHasTitle) {
      return Container(
        padding: EdgeInsets.symmetric(horizontal: 8.0),
        child: Text(
          "${widget.title}",
          textAlign: TextAlign.center,
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(
            fontSize: 17,
            fontWeight: FontWeight.w600,
            fontStyle: FontStyle.normal,
            color: Color(0xFF1A1A1A),
            decoration: TextDecoration.none,
          ),
        ),
      );
    }

    return Container();
  }

  Widget _buildContentWidget() {
    bool aHasContent = _hasContent();
    if (aHasContent) {
      return Container(
        padding: EdgeInsets.symmetric(horizontal: 8.0),
        child: Text(
          "${widget.content}",
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w500,
            fontStyle: FontStyle.normal,
            color: Color(0xFF333333),
            decoration: TextDecoration.none,
          ),
        ),
      );
    }

    return Container();
  }

  Widget _buildItemWidget() {
    if (widget.children != null && widget.children!.isNotEmpty) {
      return Container(
        height: 44.0,
        child: Row(
          children: widget.children!.map((res) {
            int index = widget.children!.indexOf(res);
            return Expanded(
              flex: 1,
              child: GestureDetector(
                onTap: () {
                  Navigator.pop(context);
                  widget.onTap(index);
                },
                child: Container(
                  height: 44,
                  alignment: Alignment.center,
                  child: res,
                  decoration: BoxDecoration(
                    border: Border(
                      right: BorderSide(
                        color: Color(0xFFF5F5F5),
                        width: 1,
                      ),
                    ),
                  ),
                ),
              ),
            );
          }).toList(),
        ),
      );
    }

    if (widget.itemTitles != null && widget.itemTitles!.isNotEmpty) {
      return Container(
        height: 44,
        child: Row(
          children: widget.itemTitles!.map((res) {
            int index = widget.itemTitles!.indexOf(res);
            return buildItem(res, index);
          }).toList(),
        ),
      );
    }

    return Container();
  }

  Widget buildItem(DialogItem item, int index) {
    String? title = item.title;
    String? color = item.color;
    Color textColor = ColorUtil.hexColor(0x333333);
    if (color != null && color.isNotEmpty) {
      textColor = ColorUtil.hexColorString(color);
    }
    return Expanded(
      flex: 1,
      child: GestureDetector(
        onTap: () {
          Navigator.pop(context);
          widget.onTap(index);
        },
        child: Container(
          height: 44,
          alignment: Alignment.center,
          child: Text(
            "${title}",
            style: TextStyle(
              color: textColor,
              fontSize: 16,
            ),
          ),
          decoration: BoxDecoration(
            border: Border(
              right: BorderSide(
                color: Color(0xFFF5F5F5),
                width: 1,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

二、定义sheet底部弹窗内容

底部弹窗内容一般为选项,分为多个选项,最后为取消按钮。

class ShowSheetDialog extends StatefulWidget {
  const ShowSheetDialog({
    Key? key,
    required this.onTap,
    required this.items,
    required this.title,
    this.cancelTitle,
  }) : super(key: key);

  //按钮title
  final List<DialogItem> items;

  //点击事件回调 0开始
  final Function onTap;

  //标题 可选
  final String title;

  //取消 可选
  final String? cancelTitle;

  
  State<ShowSheetDialog> createState() => _ShowSheetDialogState();
}

class _ShowSheetDialogState extends State<ShowSheetDialog> {
  
  Widget build(BuildContext context) {
    double viewPaddingBottom = MediaQuery.of(context).viewPadding.bottom;

    return ClipRRect(
      borderRadius: BorderRadius.only(
        topLeft: Radius.circular(8.0),
        topRight: Radius.circular(8.0),
      ),
      child: Container(
        color: ColorUtil.hexColor(0xf7f7f7),
        padding: EdgeInsets.only(bottom: viewPaddingBottom),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            _itemTitle(context),
            Column(
              mainAxisSize: MainAxisSize.min,
              children: widget.items.map((item) {
                int index = widget.items.indexOf(item);
                return GestureDetector(
                  onTap: () {
                    Navigator.pop(context);
                    if (widget.onTap != null) {
                      widget.onTap(index);
                    }
                  },
                  child: _itemCreate(item),
                );
              }).toList(),
            ),
            GestureDetector(
              child: Padding(
                padding: EdgeInsets.only(top: 10),
                child: _itemCreate(DialogItem(
                    title: widget.cancelTitle ?? "取消", color: "333333")),
              ),
              onTap: () {
                Navigator.pop(context);
              },
            )
          ],
        ),
      ),
    );
  }

  Widget _itemTitle(BuildContext context) {
    //有标题的情况下
    if (widget.title != null && widget.title.isNotEmpty) {
      return Container(
        alignment: Alignment.center,
        width: MediaQuery.of(context).size.width,
        height: 40,
        child: Text(
          "${widget.title}",
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: 14,
            fontWeight: FontWeight.w500,
            fontStyle: FontStyle.normal,
            color: ColorUtil.hexColor(0x777777),
            decoration: TextDecoration.none,
          ),
        ),
      );
    }

    return Container();
  }

  Widget _itemCreate(DialogItem item) {
    String title = item.title ?? "";
    String? color = item.color;
    Color textColor = ColorUtil.hexColor(0x333333);
    if (color != null && color.isNotEmpty) {
      textColor = ColorUtil.hexColorString(color);
    }

    return Container(
      height: 50,
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: Text(
          "${title}",
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w500,
            fontStyle: FontStyle.normal,
            color: textColor,
            decoration: TextDecoration.none,
          ),
        ),
      ),
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border(
          top: BorderSide(
            color: ColorUtil.hexColor(0xf7f7f7),
            width: 1.0,
          ),
        ),
      ),
    );
  }
}

三、调用flutter的showDialog方法弹窗

showDialog方法弹窗

/// 显示对话框的内容
class ShowDialogContent {
  String? title;
  String? message;
  String? ok;
  String? cancel;
  String? okColor;
  String? cancelColor;

  ShowDialogContent({this.title, this.message, this.ok, this.cancel});

  ShowDialogContent.fromJson(Map<String, dynamic> json) {
    title = json['title'];
    message = json['message'];
    ok = json['ok'];
    okColor = json['okColor'];
    cancel = json['cancel'];
    cancelColor = json['cancelColor'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['title'] = this.title;
    data['message'] = this.message;
    data['ok'] = this.ok;
    data['okColor'] = this.okColor;
    data['cancel'] = this.cancel;
    data['cancelColor'] = this.cancelColor;
    return data;
  }
}

class DialogUtil {
//显示中间弹窗
  static void popDialog(BuildContext context, Widget widget) {
    showDialog(
        context: context,
        barrierDismissible: true,
        builder: (ctx) {
          return widget;
        });
  }

  //返回上一级
  static void pop(BuildContext context) {
    Navigator.pop(context);
  }

// 显示处理弹出框
  static void showAlertDialog(
      {required ShowDialogContent dialogContent, OnDialogCallback? callback}) {
    DialogUtil.popDialog(
      OneContext().context!,
      ShowAlertDialog(
        title: dialogContent.title,
        content: dialogContent.message,
        onTap: (int index) {
          Map result = Map();
          result["index"] = index;
          if (callback != null) {
            callback(result);
          }
        },
        children: [
          Text(
            dialogContent.cancel ?? "",
            textAlign: TextAlign.center,
            softWrap: true,
            style: TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.w500,
              fontStyle: FontStyle.normal,
              color: dialogContent.cancelColor != null
                  ? ColorUtil.hexColorString(dialogContent.cancelColor!)
                  : ColorUtil.hexColorString("333333"),
              decoration: TextDecoration.none,
            ),
          ),
          Text(
            dialogContent.ok ?? "",
            textAlign: TextAlign.center,
            softWrap: true,
            style: TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.w500,
              fontStyle: FontStyle.normal,
              color: dialogContent.okColor != null
                  ? ColorUtil.hexColorString(dialogContent.okColor!)
                  : ColorUtil.hexColorString("333333"),
              decoration: TextDecoration.none,
            ),
          ),
        ],
      ),
    );
  }
}

四、调用flutter的bottomSheetDialog方法底部弹窗

class DialogUtil {
	
  //显示底部弹窗
  static void bottomSheetDialog(
    BuildContext context,
    Widget widget, {
    bool? isScrollControlled,
    bool? enableDrag,
    Color? backgroundColor,
  }) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: isScrollControlled ?? true,
      enableDrag: enableDrag ?? true,
      backgroundColor: backgroundColor ?? Colors.white,
      builder: (ctx) {
        return widget;
      },
    );
  }

  // 显示处理chekbox
  static void showCheckBox(
      {required String title,
      required List<Map> optionList,
      String? cancelTitle,
      OnDialogCallback? callback}) {
    // {"title":"标题","titleColor":"FFFFFF"}
    List<DialogItem> items = [];
    for (Map map in optionList) {
      String? title = map["title"];
      String? titleColor = map["titleColor"];
      DialogItem item = DialogItem(title: title, color: titleColor);
      items.add(item);
    }

    DialogUtil.bottomSheetDialog(
      OneContext().context!,
      ShowSheetDialog(
        onTap: (int index) {
          Map result = Map();
          result["index"] = index;
          if (callback != null) {
            callback(result);
          }
        },
        items: items,
        title: title,
        cancelTitle: cancelTitle,
      ),
      enableDrag: false,
      backgroundColor: Colors.transparent,
    );
  }

}

五、小结

flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果,使用到了flutter的showDialog与showModalBottomSheet来显示对话框与屏幕下方弹出一个对话框功能。

学习记录,每天不停进步。文章来源地址https://www.toymoban.com/news/detail-559703.html

到了这里,关于flutter开发实战-flutter实现类似iOS的Alert提示框与sheet菜单效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • flutter开发实战-inappwebview实现flutter与Javascript方法调用

    flutter开发实战-inappwebview实现flutter与Javascript方法调用 在使用inappwebview时候,需要flutter端与JS进行交互,调用相应的方法,在inappwebview中的JavaScript Handlers。 要添加JavaScript Handlers,可以使用InAppWebViewController.addJavaScriptHandler方法,在该方法中定义handlerName和JavaScript端调用它时要

    2024年02月03日
    浏览(35)
  • flutter开发实战-事件总线EventBus实现

    flutter开发实战-事件总线EventBus实现 在开发中,经常会需要一个广播机制,用以跨Widget事件通知。 事件总线 实现了订阅者模式,订阅者模式包含发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件。 实现eventBus 在工程的pubspec.yaml引入库 1.使用event_bus库 创建一

    2024年02月15日
    浏览(31)
  • flutter开发实战-MethodChannel实现flutter与原生Android双向通信

    flutter开发实战-MethodChannel实现flutter与原生Android双向通信 最近开发中需要原生Android与flutter实现通信,这里使用的MethodChannel MethodChannel:用于传递方法调用(method invocation)。 通道的客户端和宿主端通过传递给通道构造函数的通道名称进行连接 一个应用中所使用的所有通道名称

    2024年02月13日
    浏览(27)
  • flutter开发实战-dio文件下载实现

    flutter开发实战-dio文件下载实现 在开发中,需要下载文件,这里使用的是dio dio 是一个强大的 Dart HTTP 请求库,支持全局配置、Restful API、FormData、拦截器、 请求取消、Cookie 管理、文件上传/下载、超时以及自定义适配器等。 在工程中pubspec.yaml引入dio 我们对dio进行封装 文件下

    2024年02月11日
    浏览(36)
  • flutter开发实战-Universal Links配置及flutter微信分享实现

    flutter开发实战-Universal Links配置及flutter微信分享实现 在最近开发中碰到了需要实现微信分享,在iOS端需要配置UniversalLink,在分享使用fluwx插件来实现微信分享功能。 1.1、什么是UniversalLink Universal link 是Apple在iOS9推出的一种能够方便的通过传统HTTPS链接来启动APP的功能,可以使

    2024年01月19日
    浏览(39)
  • flutter开发实战-inappwebview实现flutter与Javascript的交互JSBridge

    flutter开发实战-inappwebview实现flutter与Javascript的交互JSBridge 在使用webview中,需要实现flutter与Javascript交互,在使用webview_flutter插件的时候,整理了一下webview与Javascript的交互JSBridge,具体可以查看 https://blog.csdn.net/gloryFlow/article/details/131683122 这里使用inappwebview插件来实现flutter与

    2024年02月08日
    浏览(34)
  • flutter开发实战-指纹、面容ID验证插件实现

    flutter开发实战-指纹、面容ID验证插件实现 在iOS开发中,经常出现需要指纹、面容ID验证的功能。 指纹、面容ID是一种基于用生物识别技术,通过扫描用户的面部特征来验证用户身份。 在iOS中实现指纹、面容ID验证功能,步骤如下 2.1 info.plist配置 在info.plist中配置允许访问FAC

    2024年02月13日
    浏览(37)
  • flutter开发实战-RepaintBoundary实现Widget截图功能

    flutter开发实战-RepaintBoundary实现Widget截图功能 在开发中,遇到需要使用截图,像iOS可以截图UIView获取到UIImage,在flutter中可以使用RepaintBoundary实现截图功能 相机拍摄的图片: RepaintBoundary截图后的图片 RepaintBoundary是绘制边界。 如果CustomPaint有子节点,为了避免子节点不必要的

    2024年02月15日
    浏览(35)
  • flutter开发实战-实现首页分类目录入口切换功能

    。 在开发中经常遇到首页的分类入口,如美团的美食团购、打车等入口,左右切换还可以分页更多展示。 在pubspec.yaml引入 由于我这里按照一页8条展示,两行四列展示格式。 当列表list传入的控件时候,一共的页数为 通过列表,一页数量计算每一页应该展示多少个按钮。 一

    2024年02月14日
    浏览(37)
  • flutter开发实战-实现推送功能Push Notification

    flutter开发实战-实现推送功能Push Notification 推送服务现在可以说是所有 App 的标配了,最近在Flutter工程项目上实现推送功能。flutter上实现推送功能需要依赖原生的功能,需要插件实现,这里使用的是极光推送的服务。 效果图如下 在使用极光推送功能时,需要使用的是极光提

    2024年02月16日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包