Flutter自定义弹窗Dialog效果
antu58 人气:0主要是基于系统的dialog机制做一些使用限制和自定义UI的优化
核心代码:
class CustomDialog { static void show(BuildContext context, Widget Function(BuildContext ctx, void Function() dismiss)builder, {bool cancellable = false}) { showDialog( context: context, barrierDismissible: cancellable, builder: (ctx) { return WillPopScope( child: Dialog( child: builder(ctx, () => Navigator.of(ctx).pop()), backgroundColor: Colors.transparent, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(0.0))), elevation: 0, alignment: Alignment.center, ), onWillPop: () async => cancellable, ); }, ); } static void showBottomSheet(BuildContext context, Widget Function(BuildContext ctx, void Function() dismiss)builder, {bool cancellable = true}) { showModalBottomSheet( context: context, isDismissible: cancellable, enableDrag: cancellable, isScrollControlled: true, builder: (BuildContext ctx) { return WillPopScope( child: builder(ctx, () => Navigator.of(ctx).pop()), onWillPop: () async => cancellable, ); }, //不设置会默认使用屏幕最大宽度而不是子组件宽度 constraints: const BoxConstraints(minWidth: 0, minHeight: 0, maxWidth: double.infinity, maxHeight: double.infinity), backgroundColor: Colors.transparent, ); } }
使用:
import 'dart:async'; import 'package:flutter/material.dart'; class DialogTestPage extends StatefulWidget { const DialogTestPage({Key? key}) : super(key: key); @override State<StatefulWidget> createState() => _DialogTestState(); } class _DialogTestState extends State<DialogTestPage> { @override Widget build(BuildContext context) { return Scaffold( body: Column(children: [ const SizedBox(height: 0, width: double.infinity,), TextButton( child: const Text("show dialog"), onPressed: () => showCustomDialog(), ), TextButton( child: const Text("show delay dialog"), onPressed: () => showDelayDialog(), ), TextButton( child: const Text("show sheet"), onPressed: () => showSheetDialog(), ), ], mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center,), ); } void showCustomDialog() { CustomDialog.show(context, (context, dismiss) { return Container( width: 200, height: 100, color: Colors.white, child: Center(child: TextButton(onPressed: () => dismiss(), child: const Text("POP")),), ); }); } void showSheetDialog() { CustomDialog.showBottomSheet(context, (ctx, dismiss) { return Container( height: 300, color: Colors.white, child: Center(child: TextButton(onPressed: () => dismiss(), child: const Text("POP")),), margin: const EdgeInsets.all(20), ); }); } void showDelayDialog() { CustomDialog.show(context, (context, dismiss) { //延时关闭 Timer(const Duration(seconds: 2), () => dismiss()); return Container( width: 200, height: 100, color: Colors.yellow, child: const Center(child: Text("等待"),), ); }, cancellable: true); } }
其中show方法中使用到的Dialog默认使用material组件库的,如果觉得有不合理的尺寸约束,可替换我修改过的Dialog组件,有其他需求也可在此定制,为什么不直接放弃使用此组件?主要涉及到其路由跳转中的一些动画布局之类的。
class Dialog extends StatelessWidget { const Dialog({ Key? key, this.backgroundColor, this.elevation, this.insetAnimationDuration = const Duration(milliseconds: 100), this.insetAnimationCurve = Curves.decelerate, this.insetPadding = const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), this.clipBehavior = Clip.none, this.shape, this.alignment, this.child, }) : super(key: key); final Color? backgroundColor; final double? elevation; final Duration insetAnimationDuration; final Curve insetAnimationCurve; final EdgeInsets? insetPadding; final Clip clipBehavior; final ShapeBorder? shape; final AlignmentGeometry? alignment; final Widget? child; static const RoundedRectangleBorder _defaultDialogShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))); static const double _defaultElevation = 24.0; @override Widget build(BuildContext context) { final DialogTheme dialogTheme = DialogTheme.of(context); final EdgeInsets effectivePadding = MediaQuery.of(context).viewInsets + (insetPadding ?? EdgeInsets.zero); return AnimatedPadding( padding: effectivePadding, duration: insetAnimationDuration, curve: insetAnimationCurve, child: MediaQuery.removeViewInsets( removeLeft: true, removeTop: true, removeRight: true, removeBottom: true, context: context, child: Align( alignment: alignment ?? dialogTheme.alignment ?? Alignment.center, child: Material( color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor, elevation: elevation ?? dialogTheme.elevation ?? _defaultElevation, shape: shape ?? dialogTheme.shape ?? _defaultDialogShape, type: MaterialType.card, clipBehavior: clipBehavior, child: child, ), ), ), ); } }
加载全部内容