草庐IT

Flutter简易弹窗

秦汉春秋 2023-07-24 原文

高温限电,疫情防控,一波未平,一波又起。
学习是不可能学习的,只能在居家摸鱼才能勉强维持生活这样子。

Flutter中有集成的弹窗方法,大致是这样:

  void showPopup() {
    showModalBottomSheet(
        context: context,
        shape:
            RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
        builder: (BuildContext context) {
          return Container(
            color: Colors.amber,
            child: Column(
              children: [
                ElevatedButton(onPressed: () {}, child: Text("1")),
                ElevatedButton(onPressed: () {}, child: Text("2")),
              ],
            ),
          );
        });
  }

效果大致如下:

就是使用showModalBottomSheet或类似的API,但相对来说可定制的参数较少,比如较为重要的位置是难以控制的,而且也不美观。
当然,不自由的组件很难美观起来。

所以想办法自定义一下。
自定义也简单,看看showModalBottomSheet的源码,依葫芦画瓢改改就行,大多自定义API都可以这么干。

而showModalBottomSheet的源码是这样的:

Future<T?> showModalBottomSheet<T>({
  required BuildContext context,
  required WidgetBuilder builder,
  Color? backgroundColor,
  double? elevation,
  ShapeBorder? shape,
  Clip? clipBehavior,
  BoxConstraints? constraints,
  Color? barrierColor,
  bool isScrollControlled = false,
  bool useRootNavigator = false,
  bool isDismissible = true,
  bool enableDrag = true,
  RouteSettings? routeSettings,
  AnimationController? transitionAnimationController,
  Offset? anchorPoint,
}) {
  assert(context != null);
  assert(builder != null);
  assert(isScrollControlled != null);
  assert(useRootNavigator != null);
  assert(isDismissible != null);
  assert(enableDrag != null);
  assert(debugCheckHasMediaQuery(context));
  assert(debugCheckHasMaterialLocalizations(context));

  final NavigatorState navigator = Navigator.of(context, rootNavigator: useRootNavigator);
  return navigator.push(_ModalBottomSheetRoute<T>(
    builder: builder,
    capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
    isScrollControlled: isScrollControlled,
    barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
    backgroundColor: backgroundColor,
    elevation: elevation,
    shape: shape,
    clipBehavior: clipBehavior,
    constraints: constraints,
    isDismissible: isDismissible,
    modalBarrierColor: barrierColor,
    enableDrag: enableDrag,
    settings: routeSettings,
    transitionAnimationController: transitionAnimationController,
    anchorPoint: anchorPoint,
  ));
}

一下就明白了,弹窗是弹出另一页,自然得另有路由:

navigator.push(_ModalBottomSheetRoute);

接下来抄抄_ModalBottomSheetRoute就行。

class PopupFreeWindow extends PopupRoute {
  ///子组件
  final Widget child;
  ///切换动画时长,必要属性
  final Duration duration;
  ///间隔,用于微调位置
  final EdgeInsets margin;
  ///分布,用于控制大体位置 
  final Alignment alignment;
  ///外围遮罩背景色
  Color? outerBackgroudColor;

  ///子控件具体宽度
  double width;
  ///子控件具体高度
  double height;
  ///宽度比例
  double widthFactor;
  ///高度比例 
  double heightFactor;
  ///是否点击外围收起弹窗
  bool dismissable;

  PopupFreeWindow(
      {required this.child,
      this.duration = const Duration(milliseconds: 300),
      this.alignment = Alignment.bottomCenter,
      this.margin =
          const EdgeInsets.only(bottom: kBottomNavigationBarHeight * 1.5),
      this.widthFactor = 0.95,
      this.heightFactor = 0.3,
      this.width = 0,
      this.height = 0,
      this.dismissable = true});

  @override
  Color? get barrierColor =>
      outerBackgroudColor ?? Colors.black.withOpacity(0.3);

  @override
  bool get barrierDismissible => dismissable;

  @override
  String? get barrierLabel => null;

  @override
  Duration get transitionDuration => duration;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    Widget? content;
    if (width > 0 && height >= 0) {
      content = Container(
        alignment: alignment,
        margin: margin,
        child: Container(
          child: child,
          width: width,
          height: height,
        ),
      );
    } else {
      content = FractionallySizedBox(
          widthFactor: widthFactor,
          heightFactor: heightFactor,
          child: Container(
            child: child,
            margin: margin,
          ),
          alignment: alignment);
    }
    return FadeTransition(
        opacity: animation,
        child: SafeArea(
          child: content,
        ));
  }

}

测试代码:

void showbottom() {
    final size = MediaQuery.of(context).size;
    final width = size.width;
    final height = size.height;
    print("screen w=$width,h=$height");
    Navigator.of(context).push(PopupFreeWindow(
      // widthFactor: 0.95,
      // heightFactor: 0.4,
      height: 200,
      width: width - 30,
      child: ChatBubble(
        direction: ArrowDirection.bottom,
        arrowWidth: 30,
        arrowHeight: 20,
        conicWeight: 4.5,
        child: GridMenu(),
      ),
    ));
  }

根据真实的屏幕大小,来定制弹窗的大小,默认的Alignment为底部,可以调整,默认底部的间隔为状态栏的1.5倍,可以调整,这里这么写是为了结合上一篇博客中的ChatBubble,实现底部悬浮菜单的效果。
实际上都可以自行定义。
效果见下图。

以上。
(继续摸鱼去了~)

有关Flutter简易弹窗的更多相关文章

  1. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  2. Flutter 环境变量配置和flutter doctor中的错误解决 - 2

    一、环境变量右键点击我的电脑-属性:然后找到环境变量 1.Android的SDK不在C盘的话需要额外配这个到用户环境变量:ANDROID_HOMED:\AndroidSDK2.然后在系统变量:Path中添加一条这样的值        D:\Flutter\flutter\bin             这个值写flutter包解压的实际地址即可 3.在系统变量中添加两个镜像变量:        变量名:FLUTTER_STORAGE_BASE_URL      变量值:https://storage.flutter-io.cn        变量名:PUB_HOSTED_URL      变量

  3. 微信小程序 webview页面分享弹窗 - 2

    微信小程序webview中使用cover-view展示分享弹窗公司业务需要在webview中添加分享弹窗,可以发送给朋友及生成海报分享,因为好几个详情都需要这个功能,因此抽离了share-sheet的组件,ui效果如下图:点击分享,显示以下弹窗share-sheet.wxml如下:{!show}}"catchtouchmove="poptouchmove">发送给朋友生成海报取消share-sheet.js如下:Component({options:{addGlobalClass:true,},/***组件的属性列表*/properties:{//控制弹窗显示与否show:{type:Bool

  4. 【JavaScript】手撕前端面试题:对象参数浅拷贝 | 简易深拷贝 | 完整深拷贝 - 2

    🖥️NodeJS专栏:Node.js从入门到精通🖥️博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述)🖥️TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结)🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬👉你的一键三连是我更新的最大动力❤️!文章目录1、浅拷贝要求思路代码2、简易深拷贝要求思路代码3、完整深拷贝要求思路代码1、浅拷贝要求补全JavaScript代码,要求实现一个对象参数的浅拷贝并返回拷贝之后的新对象。注意:参数可能包含函数、正则、日期、ES6新对象是对对象的参数进行浅拷贝,并不是直接对整个对象进行浅拷贝(整个

  5. 微机课设 | 基于STC15单片机的简易数字密码锁设计 - 2

    在日常的生活和工作中,住宅与部门的安全防范、单位的文件档案、财务报表以及一些个人资料的保存多以加锁的办法来解决。若使用传统的机械式钥匙开锁,人们常需携带多把钥匙, 使用极不方便, 且钥匙丢失后安全性即大打折扣。在安全技术防范领域,具有防盗报警功能的电子密码锁逐渐代替了传统的机械式密码锁,电子密码锁具有安全性高、成本低、功耗低、易操作等优点。本文主要介绍运用51单片机设计数字密码锁的方法。本设计采用自上而下的数字系统设计方法,将数字密码锁系统分解为若干子系统,并且进一步细划为若干模块,然后用C语言来设计这些模块,通过KEIL软件编译,并且进行实机调试。调试结果表明:该数字密码锁能够效验4位十进制

  6. javascript - 如何防止IE11弹窗(您确定要离开此页面吗) - 2

    我正在处理一个页面,除了一个可供选择的下拉菜单外,我没有任何可输入的内容,但是在IE11中,当我尝试转到下一页时,它会弹出消息。我想防止这种弹出窗口发生。所以我只是想知道在IE11中弹出的默认行为是什么(因为它没有出现在Chrome或Firefox中)以及如何防止弹出 最佳答案 要问的一个更重要的问题是:“为什么IE11会弹出该警报?”。您是否为不安全的页面留下了安全的页面?IE。确保通过不明确指定协议(protocol)来调用安全预订API,或让浏览器选择:varurl='//api.booking_site.url/api_en

  7. javascript - 弹窗使用knockout js - 2

    我正在将我的一个旧jquery插件从DOMjungle迁移到这个奇特的mvvm框架knockout。我应该使用哪种技术来正确显示弹出容器?我必须“通过电话”填充它,因为我每次都会收到一个json提要。我尝试了一种使用with绑定(bind)的方法,但它仍会尝试在其第一次运行时填充部分内容。//Somebindingshere. 最佳答案 它也可以在没有自定义绑定(bind)的情况下完成。示例如下查看模型代码:self.showAlert=function(title,message,closeButtonText){self.pop

  8. javascript - 弹窗返回值 - 2

    我希望有人可以帮助我解决这个问题。我正在尝试做的是将弹出窗口中的值返回到使用javascript启动它的父窗口中。我试过的是调用(如在各种网站上所读)window.opener.document.forms[0].textField.value='value'但是虽然这不会产生任何错误,但它不会更改字段值。我曾尝试在网上搜索此问题的解决方案,但谷歌上有太多与“弹出返回值”相关的网站,结果可追溯到2000年,许多网站似乎相互冲突,所以我有点困惑。理想情况下,我更愿意做的是让弹出窗口等待做出决定(是或否),然后将true或false值从父窗口返回给调用函数。这样做的原因是,我有一个表单使用

  9. 微信小程序开发(八):page-container弹窗与share-element动画 - 2

    page-container页面容器,可以在当前页面中弹出一个半屏的弹窗、或者在页面内加载一个全屏的子页面。当page-container组件显示时,用户进行返回操作时会关闭page-container容器,而不会关闭当前页面。每个页面最多只能显示一个page-container,如果在一个页面代码中定义了多个page-container,只有文档流中的第一个page-container能正常显示。属性show:是否显示page-container组件duration:动画时长z-index:默认100,显示在其他元素的上层overlay:是否显示遮罩层position:page-contai

  10. javascript - 用户登录前的弹窗检测 - 2

    有没有一种好方法可以确定一个人是否启用了弹出窗口阻止程序?我需要维护一个web应用程序,不幸的是,它有大量的弹出窗口,我需要检查用户是否启用了弹出窗口阻止程序。我发现这样做的唯一方法是从javascript打开一个窗口,检查它是否打开以确定是否启用了阻止程序,然后立即将其关闭。这有点烦人,因为没有启用它的用户会在窗口立即打开和关闭时在屏幕上看到一个小的闪光。是否有任何其他非侵入性方法可以实现此目的? 最佳答案 阅读DetectapopupblockerusingJavascript:基本上,您检查“window.open”方法是否返

随机推荐