首页 > 其他分享 >Flutter功能性组件(1):对话框

Flutter功能性组件(1):对话框

时间:2024-10-11 16:12:23浏览次数:10  
标签:const key 对话框 Text context child 组件 Flutter

Material 库提供了三种基本对话框组件

  • AlertDialog 通常用于提示型对话框
  • SimpleDialog 通常用于列表型对话框
  • Dialog 通常用于自定义布局元素的对话框

弹出对话框时,调用 showDialog 函数,将对话框控件传入,由于对话框本身是路由,所以关闭对话框时,需使用 Navigator.of(context).pop()

一、AlertDialog(提示对话框)

AlertDialog 是一个 Flutter widget,用于显示弹出式对话框,通常用于向用户显示重要信息或要求他们进行一些确认操作。

属性解析:

const AlertDialog({
  super.key, // 控件的键值,用于标识控件。
  this.icon, // 对话框顶部的图标。
  this.iconPadding, // 图标的内边距。
  this.iconColor, // 图标的颜色。
  this.title, // 对话框的标题。
  this.titlePadding, // 标题的内边距。
  this.titleTextStyle, // 标题的文本样式。
  this.content, // 对话框的内容。
  this.contentPadding, // 内容的内边距。
  this.contentTextStyle, 内容的文本样式。
    this.actions, // 对话框底部的动作按钮列表。
  this.actionsPadding, // 动作按钮的内边距。
  this.actionsAlignment, // 动作按钮在溢出时的对齐方式。
  this.actionsOverflowAlignment, // 动作按钮溢出时的排列方向。
  this.actionsOverflowDirection, // 动作按钮在溢出时的间隔。
  this.actionsOverflowButtonSpacing, // 动作按钮在溢出时的间隔。
  this.buttonPadding, // 按钮的内边距。
  this.backgroundColor, // 对话框的背景颜色。
  this.elevation, // 对话框的阴影高度。
  this.shadowColor, // 对话框阴影的颜色。
  this.surfaceTintColor, // 表面色调的颜色。
  this.semanticLabel, // 屏幕阅读器使用的语义标签。
  this.insetPadding = _defaultInsetPadding, // 对话框与屏幕边缘的间距。
  this.clipBehavior = Clip.none, // 对话框的剪裁行为。
  this.shape, // 对话框的外形。
  this.alignment, // :对话框相对于其父控件的对齐方式。
  this.scrollable = false, // 如果内容超出可视区域,是否应该滚动。默认为 false。
})

二、使用showDialog显示对话框

在介绍其他两种基本对话框之前,先介绍一下 showDialog,方便下面贴出显示对话框的示例。

showDialog<T?>是一个 Flutter 方法,用于显示模态对话框。

属性解析

Future<T?> showDialog<T>({
  required BuildContext context, // 表示对话框所处的上下文,通常来自当前 widget。
  required WidgetBuilder builder, // 用于构建对话框内容的函数。它传递一个 BuildContext 并返回一个 Widget,这通常是对话框的主体。
  bool barrierDismissible = true, // 指示用户点击屏幕背景(对话框外部)时是否关闭对话框。默认为 true。
  Color? barrierColor, // 对话框背景障碍物(屏幕其余部分)的颜色。
  String? barrierLabel, // 屏障的语义标签,用于无障碍功能。
  bool useSafeArea = true, // 是否考虑安全区域(如异形屏幕的凹槽、状态栏等)。默认为 true。
  bool useRootNavigator = true, // 是否使用根导航器来推送对话框。默认为 true。
  RouteSettings? routeSettings, // 传递给对话框路由的配置信息,如名称和参数。
  Offset? anchorPoint, // 指定对话框弹出的锚点位置。
  TraversalEdgeBehavior? traversalEdgeBehavior, // 定义对话框边缘遍历行为。
})

(1)直接显示对话框

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          showDialog(
              context: context,
              builder: (BuildContext context) => AlertDialog(
                    title: const Text('标题'),
                    content: const Text('我是对话框'),
                    actions: [
                      OutlinedButton(
                          onPressed: () {
                            print('取消');
                            Navigator.of(context).pop();
                          },
                          child: Text('取消')),
                      OutlinedButton(
                          onPressed: () {
                            print('确定');
                            Navigator.of(context).pop();
                          },
                          child: Text('确定')),
                    ],
                  ));
        },
        child: Text("弹出对话框"),
      ), // 使用你的组件
    );
  }
}

(2)使用函数显示对话框

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          _showAlertDialog(context);
        },
        child: Text("弹出对话框"),
      ), // 使用你的组件
    );
  }
}

Future<void> _showAlertDialog(BuildContext context) async {
  return showDialog<void>(
    context: context,
    barrierDismissible: false, // 设置为false,点击背景不会关闭
    builder: (BuildContext context) {
      return AlertDialog(
        title: const Text('标题'),
        content: const Text('我是对话框'),
        actions: [
          OutlinedButton(
              onPressed: () {
                print('取消');
                Navigator.of(context).pop();
              },
              child: Text('取消')),
          OutlinedButton(
              onPressed: () {
                print('确定');
                Navigator.of(context).pop();
              },
              child: Text('确定')),
        ],
      );
    },
  );
}

点击按钮后调用 _showMyDialog 函数来显示对话框。效果图如下所示:
Flutter_dialog_A.gif


三、返回值的处理

用户在点击退出登录时,通常的做法就是弹框用来确认是否退出登录,返回值是 bool 类型,为 true 表示退出登录,反之不需要退出,这个时候应该怎处理这个 bool 类型的返回值呢?

我们知道 showDialog 本身返回的就是 Future 对象,如果需要在 Dialog 关闭后继续执行一些其它逻辑,我们可以使用 awaitasync 关键字来接收返回数据处理异步操作,下面来看看该怎么实现。

Future<bool?> _showAlertDialog(BuildContext context) {
  return showDialog<bool>(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text("Logout"),
        content: const Text("Are you sure you want to logout?"),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(false);
            },
            child: const Text("Cancel"),
          ),
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(true);
            },
            child: const Text("Sure"),
          )
        ],
      );
    },
  );
}

利用 Navigator.of(context).pop(true) 方法来关闭对话框,并传递 true 或者 false 值作为对话框的返回结果,当点击按钮调用 _showMyDialog 弹出 Dialog

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () async {
          bool? result = await _showAlertDialog(context);
          debugPrint("Result: $result");
        },
        child: Text("弹出对话框"),
      ), // 使用你的组件
    );
  }
}

效果图如下所示:

Flutter_dialog_B.png


四、SimpleDialog(模态对话框)

SimpleDialog:用于显示一个简单的对话框,通常包含一个标题和多个选项。

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          _showSimpleDialog(context);
        },
        child: Text("弹出对话框"),
      ),
    );
  }
}

Future<bool?> _showSimpleDialog(BuildContext context) {
  return showDialog(
    context: context,
    builder: (BuildContext context) {
      return SimpleDialog(
        title: Text('选择一个选项'),
        children: <Widget>[
          SimpleDialogOption(
            onPressed: () {
              Navigator.pop(context, '选项1');
            },
            child: Text('选项1'),
          ),
          SimpleDialogOption(
            onPressed: () {
              Navigator.pop(context, '选项2');
            },
            child: Text('选项2'),
          ),
        ],
      );
    },
  );
}

效果图如下所示:

Flutter_dialog_C.png


五、AboutDialog(关于对话框)

AboutDialog 用于显示应用程序的相关信息,例如版本号、作者等。

void showAboutDialog({
  required BuildContext context, // 表示对话框所处的上下文,通常来自当前 widget。
  String? applicationName, // 应用程序的名称。如果未提供,将使用 DefaultWidgetsLocalizations.of(context).appName。
  String? applicationVersion, // 应用程序的版本。
  Widget? applicationIcon, // 应用程序的图标。
  String? applicationLegalese, // 应用程序的法律声明。
  List<Widget>? children, // 在对话框中显示的额外小部件。
  bool barrierDismissible = true, // 指示用户点击屏幕背景(对话框外部)时是否关闭对话框。默认为 true。
  Color? barrierColor, // 弹出框背景障碍物(屏幕其余部分)的颜色。
  String? barrierLabel, // 屏障的语义标签,用于无障碍功能。
  bool useRootNavigator = true, // 是否使用根导航器来推送对话框。默认为 true。
  RouteSettings? routeSettings, // 传递给对话框路由的配置信息,如名称和参数。
  Offset? anchorPoint, // 指定对话框弹出的锚点位置。
})

代码如下:

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          _showAboutDialog(context);
        },
        child: Text("弹出对话框"),
      ), // 使用你的组件
    );
  }
}

_showAboutDialog(BuildContext context) {
  showAboutDialog(
    context: context,
    applicationName: 'My Application',
    applicationVersion: '1.0.0',
    applicationIcon: Icon(Icons.info, size: 48.0),
    applicationLegalese: '© 2023 My Company. All rights reserved.',
    children: <Widget>[
      Padding(
        padding: const EdgeInsets.only(top: 16.0),
        child: Text('This is a custom about dialog.'),
      ),
    ],
  );
}

效果图如下所示:

Flutter_dialog_D.png


六、Input Dialog(输入对话框)

有时你可能需要一个简单的对话框来收集用户输入,如文本或数字。

示例:

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () async {
          String? input = await showDialog<String>(
            context: context,
            builder: (BuildContext context) {
              return InputDialog();
            },
          );
          debugPrint('用户输入: $input');
        },
        child: Text('显示输入对话框'),
      ), // 使用你的组件
    );
  }
}

class InputDialog extends StatefulWidget {
  const InputDialog({Key? key}) : super(key: key);
  @override
  _InputDialogState createState() => _InputDialogState();
}

class _InputDialogState extends State<InputDialog> {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('输入对话框'),
      content: TextField(
        controller: _controller,
        decoration: InputDecoration(hintText: '请输入内容'),
      ),
      actions: <Widget>[
        TextButton(
          onPressed: () {
            Navigator.of(context).pop(null);
          },
          child: Text('取消'),
        ),
        TextButton(
          onPressed: () {
            Navigator.of(context).pop(_controller.text);
          },
          child: Text('确定'),
        ),
      ],
    );
  }
}

效果图如下所示:

Flutter_dialog_F.png


七、自定义Dialog

Dialog 是一个 Flutter 小部件,用于显示对话框

属性解析

const Dialog({
  super.key, // 用于标识小部件的唯一键。
  this.backgroundColor, // 
  this.elevation, // 对话框的阴影高度。
  this.shadowColor, // 阴影颜色。
  this.surfaceTintColor, // 表面色调颜色。
  this.insetAnimationDuration = const Duration(milliseconds: 100), // 对话框插入动画的持续时间。默认为 Duration(milliseconds: 100)。
  this.insetAnimationCurve = Curves.decelerate, // 对话框插入动画的曲线。默认为 Curves.decelerate。
  this.insetPadding = _defaultInsetPadding, // 对话框相对于屏幕边缘的填充。默认值为 _defaultInsetPadding。
  this.clipBehavior = Clip.none, // 裁剪行为,默认值为 Clip.none。
  this.shape, // 对话框的形状,例如圆角矩形。
  this.alignment, // 对话框在屏幕上的对齐方式。
  this.child, // 对话框的子组件,通常是内容区域。
})

示例:

class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          showDialog(
            context: context,
            builder: (BuildContext context) {
              return CustomDialog();
            },
          );
        },
        child: Text("弹出对话框"),
      ), // 使用你的组件
    );
  }
}

class CustomDialog extends StatelessWidget {
  const CustomDialog({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Container(
        height: 200,
        padding: EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              '自定义对话框标题',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 16),
            Text('这是自定义对话框内容。你可以根据需要添加任何组件。'),
            SizedBox(height: 24),
            Align(
              alignment: Alignment.bottomRight,
              child: TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text('关闭'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_dialog_E.png


八、综合对话框示例

// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Dialog Page"),
        ),
        body: MyHomeBody(),
      ),
    );
  }
}

// 主页面
class MyHomeBody extends StatelessWidget {
  const MyHomeBody({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      // 垂直布局
      mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 平均分布各个 Widget
      crossAxisAlignment: CrossAxisAlignment.stretch, // 填充整个交叉轴
      mainAxisSize: MainAxisSize.max,
      children: <Widget>[
        ElevatedButton(
          onPressed: () async {
            bool? result = await _showAlertDialog(context);
            debugPrint("Result: $result");
          },
          style: ElevatedButton.styleFrom(
            minimumSize: const Size(160, 80),
          ),
          child: Text("AlertDialog(提示对话框)"),
        ),
        ElevatedButton(
          onPressed: () {
            _showSimpleDialog(context);
          },
          style: ElevatedButton.styleFrom(
            minimumSize: const Size(160, 80),
          ),
          child: Text("SimpleDialog(模态对话框)"),
        ),
        ElevatedButton(
          onPressed: () {
            _showAboutDialog(context);
          },
          style: ElevatedButton.styleFrom(
            minimumSize: const Size(160, 80),
          ),
          child: Text("AboutDialog(关于对话框)"),
        ),
        ElevatedButton(
          onPressed: () async {
            String? input = await showDialog<String>(
              context: context,
              builder: (BuildContext context) {
                return InputDialog();
              },
            );
            debugPrint("用户输入: $input");
          },
          style: ElevatedButton.styleFrom(
            minimumSize: const Size(160, 80),
          ),
          child: Text("Input Dialog(输入对话框)"),
        ),
        ElevatedButton(
          onPressed: () {
            showDialog(
              context: context,
              builder: (BuildContext context) {
                return CustomDialog();
              },
            );
          },
          style: ElevatedButton.styleFrom(
            minimumSize: const Size(160, 80),
          ),
          child: Text("自定义对话框"),
        ),
      ],
    );
  }
}

// AlertDialog(提示对话框)
Future<bool?> _showAlertDialog(BuildContext context) {
  return showDialog<bool>(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text("Logout"),
        content: const Text("Are you sure you want to logout?"),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(false);
            },
            child: const Text("Cancel"),
          ),
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(true);
            },
            child: const Text("Sure"),
          )
        ],
      );
    },
  );
}

// SimpleDialog(模态对话框)
Future<String?> _showSimpleDialog(BuildContext context) {
  return showDialog(
    context: context,
    builder: (BuildContext context) {
      return SimpleDialog(
        title: Text('选择一个选项'),
        children: <Widget>[
          SimpleDialogOption(
            onPressed: () {
              Navigator.pop(context, '选项1');
            },
            child: Text('选项1'),
          ),
          SimpleDialogOption(
            onPressed: () {
              Navigator.pop(context, '选项2');
            },
            child: Text('选项2'),
          ),
        ],
      );
    },
  );
}

// AboutDialog(关于对话框)
_showAboutDialog(BuildContext context) {
  showAboutDialog(
    context: context,
    applicationName: 'My Application',
    applicationVersion: '1.0.0',
    applicationIcon: Icon(Icons.info, size: 48.0),
    applicationLegalese: '© 2023 My Company. All rights reserved.',
    children: <Widget>[
      Padding(
        padding: const EdgeInsets.only(top: 16.0),
        child: Text('This is a custom about dialog.'),
      ),
    ],
  );
}

// Input Dialog(输入对话框)
class InputDialog extends StatefulWidget {
  const InputDialog({Key? key}) : super(key: key);
  @override
  _InputDialogState createState() => _InputDialogState();
}

class _InputDialogState extends State<InputDialog> {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('输入对话框'),
      content: TextField(
        controller: _controller,
        decoration: InputDecoration(hintText: '请输入内容'),
      ),
      actions: <Widget>[
        TextButton(
          onPressed: () {
            Navigator.of(context).pop(null);
          },
          child: Text('取消'),
        ),
        TextButton(
          onPressed: () {
            Navigator.of(context).pop(_controller.text);
          },
          child: Text('确定'),
        ),
      ],
    );
  }
}

// 自定义对话框
class CustomDialog extends StatelessWidget {
  const CustomDialog({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Container(
        height: 200,
        padding: EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              '自定义对话框标题',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 16),
            Text('这是自定义对话框内容。你可以根据需要添加任何组件。'),
            SizedBox(height: 24),
            Align(
              alignment: Alignment.bottomRight,
              child: TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text('关闭'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_dialog_H.gif


参考:

Flutter 初识:对话框和弹出层_flutter 正在发布 弹出层-CSDN博客

Flutter 中如何优雅地使用弹框 - 知乎 (zhihu.com)


标签:const,key,对话框,Text,context,child,组件,Flutter
From: https://www.cnblogs.com/linuxAndMcu/p/18458659

相关文章

  • Flutter可滚动组件(9):嵌套可滚动组件 NestedScrollView
    一、NestedScrollView上一节中,我们知道CustomScrollView只能组合Sliver,如果有孩子也是一个可滚动组件(通过SliverToBoxAdapter嵌入)且它们的滑动方向一致时便不能正常工作。为了解决这个问题,Flutter中提供了一个NestedScrollView组件,它的功能是组合(协调)两个可滚动组件,下面我......
  • Flutter功能性组件(2):弹出框
    一、showModalBottomSheet(模态底部弹出框)showModalBottomSheet用于显示一个模态底部弹出框。属性解析:Future<T?>showModalBottomSheet<T>({requiredBuildContextcontext,//表示底部弹出框所处的上下文,通常来自当前widget。requiredWidgetBuilderbuilder,//用......
  • Flutter基础组件(7):进度条
    在Flutter应用开发中,无论是处理网络请求,执行耗时任务,或是等待用户响应,我们总是需要在界面上显示进度条或者等待指示器。在这篇博客中,我们将介绍Flutter中两种常用的进度指示器:LinearProgressIndicator和CircularProgressIndicator。我们将比较它们的异同点,以及如何使用和自......
  • Flutter基础组件(6):单选按钮、复选框、单选开关
    在移动应用开发中,单选和复选是常见的用户交互模式,用于选择一个或多个选项。Flutter提供了一些内置的组件和机制,方便我们实现单选和复选功能。本文将介绍Flutter中的单选按钮(RadioButton)和复选框(Checkbox)的使用方法和示例。一、单选按钮(RadioButton)单选按钮是一种用户界面组件......
  • Flutter布局(2):弹性布局(Flex、Expanded)
    一、什么是弹性布局(Flex)什么是弹性布局(Flex)?弹性布局(Flex)是一种基于弹性盒子模型的布局方式,类似于Web开发中的Flexbox。在Flutter中,Flex组件是用于实现弹性布局的关键组件之一。Flex布局是一种简洁且强大的方式,可用于构建水平或垂直方向的弹性布局。Flex组件可以沿着水平......
  • Flutter布局(1):线性布局(Row、Column)
    所谓线性布局,即指沿水平或垂直方向排列子组件。Flutter中通过Row和Column来实现线性布局。主轴和纵轴对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。一、Row组件1.1......
  • Flutter布局(4):层叠布局(Stack、Positioned)
    层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。层叠布局允许子组件按照代码中声明的顺序堆叠起来。Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位。Stack允许子组件堆叠,而Positioned用于根据......
  • Flutter布局(3):流式布局(Wrap、Flow)
    一、简介在Flutter中,流式布局是一种常用的布局方式,用于实现动态调整子组件位置和尺寸的需求。Flutter提供了两个流式布局的组件:Wrap和Flow。其实,Flow用的实在不多呀。二、Wrap组件Wrap组件是一种流式布局,它会自动调整和换行子组件,以适应可用空间。属性Wrap组件具有......
  • Flutter布局(5):对齐与居中布局(Align、Center)
    在Flutter中,布局是构建用户界面的重要组成部分。Align和Center是两个常用的布局组件,它们都用于在父组件中对子组件进行对齐和居中。本篇博客将详细介绍Align和Center的用法、属性和适用场景,帮助你更好地理解和运用它们。一、Align:精准对齐,掌握位置Align组件用于将子组......
  • vue3父组件调用子组件方法的大坑
    父组件:<template><ChildComponentref="callChildMethod"/></template><scriptsetup>import{ref}from'vue';importChildComponentfrom'./ChildComponent.vue';constcallChildMethod=ref();......