flutter 弹窗之系列二

news2024/11/15 11:13:41

自定义弹窗(含底部抽屉)Dialog

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        crossAxisAlignment: CrossAxisAlignment.center,
        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(),
          ),
        ],
      ),
    );
  }

  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,
        margin: const EdgeInsets.all(20),
        child: Center(
          child:
              TextButton(onPressed: () => dismiss(), child: const Text("POP")),
        ),
      );
    });
  }

  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);
  }
}

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,
    );
  }
}

AlertDialog的属性

  • title:标题
  • titlePadding:标题内边距
  • titleTextStyle:标题样式
  • content:内容,推荐用SingleChildScrollView包裹
  • contentPadding:EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),内容内边距
  • contentTextStyle:内容样式
  • actions:按钮集合,可以放多个
  • actionsPadding:EdgeInsets.zero,actions内边距
  • buttonPadding:按钮内边距
  • backgroundColor:背景色
  • elevation:阴影
  • shape:形状
  • scrollable = false:

 SimpleDialog

  • title:标题
  • titlePadding:EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),标题内边距
  • titleTextStyle:标题样式
  • children:子节点
  • contentPadding:EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0),内容内边距
  • backgroundColor:背景色
  • elevation:阴影
  • shape:形状

 全局弹窗

  • pubspec.yaml增加dio依赖包
dio: any # dio依赖包

 

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {


  void _showLoadingDialog() {
    showDialog(
      context: context,
      builder: (context) {
        // 用Scaffold返回显示的内容,能跟随主题
        return Scaffold(
          backgroundColor: Colors.transparent, // 设置透明背影
          body: Center( // 居中显示
            child: Column( // 定义垂直布局
              mainAxisAlignment: MainAxisAlignment.center, // 主轴居中布局,相关介绍可以搜下flutter-ui的内容
              children: <Widget>[
                // CircularProgressIndicator自带loading效果,需要宽高设置可在外加一层sizedbox,设置宽高即可
                CircularProgressIndicator(),
                SizedBox(
                  height: 10,
                ),
                Text('loading'), // 文字
                // 触发关闭窗口
                GestureDetector(
                  child: Text('close dialog'),
                  onTap: () {
                    print('close');
                  },
                ),
              ],
            ), // 自带loading效果,需要宽高设置可在外加一层sizedbox,设置宽高即可
          ),
        );
      },
    );
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            _showLoadingDialog();
          },
          child: const Text(
            '\n点击显示弹窗一\n',
          ),
        ),
      ),
    );
  }
}

接入dio 网络请求显示弹窗

import 'package:dio/dio.dart' show Dio, InterceptorsWrapper;
import 'package:flutter_custom_widget/http/Loading.dart';

Dio? dio;

class Http {
  static Dio? instance() {
    if (dio != null) {
      return dio;// 实例化dio
    }
    dio = Dio();
    // 增加拦截器
    dio?.interceptors.add(
      InterceptorsWrapper(
        // 接口请求前数据处理
        onRequest: (options,handler) {
          Loading.before("onRequest");
        },
        // 接口成功返回时处理
        onResponse: (resp,handler) {
          Loading.complete();
        },
        // 接口报错时处理
        onError: ( error,handler) {
          Loading.complete();
        },
      ),
    );
    return dio;
  }

  /// get接口请求
  /// path: 接口地址
  static get(path) {
    return instance()?.get(path);
  }
}


import 'package:flutter/material.dart';

class Loading {
  static dynamic ctx;

  static void before(text) {
    // 请求前显示弹窗
    showDialog(
      context: ctx,
      builder: (context) {
        return Index(text: text);
      },
    );
  }

  static void complete() {
    // 完成后关闭loading窗口
    Navigator.of(ctx, rootNavigator: true).pop();
  }
}

// 弹窗内容
class Index extends StatelessWidget {
  final String? text;

  Index({Key? key, @required this.text}):super(key: key);

  @override
  Widget build(BuildContext context) {
    return  Text('$text');
  }
}

实现全局存储context

@override
Widget build(BuildContext context) {
    ......
    
    Loading.ctx = context; // 注入context

    ......

}
class Loading {
  static dynamic ctx;
  static void before(text) {
    // 请求前显示弹窗
	// showDialog(context: ctx, builder: (context) {
	//   return Index(text:text);
	// );
  }

  static void complete() {
    // 完成后关闭loading窗口
	// Navigator.of(ctx, rootNavigator: true).pop();
  }
}

实现dio请求时loading

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  @override
  Widget build(BuildContext context) {
    Loading.ctx = context; // 注入context
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            Http.get('https://blog.csdn.net/u013491829/article/details/137032263');
          },
          child: const Text(
            '\n点击进行网络加载\n',
          ),
        ),
      ),
    );
  }
}

并发请求时loading处理

并发请求,loading只需要保证有一个在当前运行。接口返回结束,只需要保证最后一个完成时,关闭loading。 

  • 使用Set有排重作用,比较使用用来管理并发请求地址。通过Set.length控制弹窗与关闭窗口。
  • 增加LoadingStatus判断是否已经有弹窗存在
  • 修改onRequest/onResponse/onError入参
import 'package:flutter/material.dart';

Set dict = Set();
bool loadingStatus = false;
class Loading {
  static dynamic ctx;

  static void before(uri, text) {
    dict.add(uri); // 放入set变量中
    // 已有弹窗,则不再显示弹窗, dict.length >= 2 保证了有一个执行弹窗即可,
    if (loadingStatus == true || dict.length >= 2) {
      return ;
    }
    loadingStatus = true; // 修改状态
    // 请求前显示弹窗
    showDialog(
      context: ctx,
      builder: (context) {
        return Index(text: text);
      },
    );
  }

  static void complete(uri) {
    dict.remove(uri);
    // 所有接口接口返回并有弹窗
    if (dict.length == 0 && loadingStatus == true) {
      loadingStatus = false; // 修改状态
      // 完成后关闭loading窗口
      Navigator.of(ctx, rootNavigator: true).pop();
    }
  }
}

 案例 切换到分支flutter_custom_widget

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新能源汽车充电桩主板各模块成本占比解析

汽车充电桩主板是汽车充电桩的重要组件&#xff0c;主要由微处理器模块、通信模块、控制模块、安全保护模块、传感器模块等多个模块构成。深入探究各模块在总成本中的比重&#xff0c;我们可以更好地优化成本结构、提高生产效率&#xff0c;并为未来的技术创新和市场需求变化做…

Spring - AOP/事务 实现原理

AOP 基本概念 官方文档&#xff1a; Aspect Oriented Programming with Spring Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions: within - limits matching to join points within certain types (simply the exec…

2核4g服务器能支持多少人访问?阿里云2核4g服务器在线人数

阿里云2核4G服务器多少钱一年&#xff1f;2核4G配置1个月多少钱&#xff1f;2核4G服务器30元3个月、轻量应用服务器2核4G4M带宽165元一年、企业用户2核4G5M带宽199元一年。可以在阿里云CLUB中心查看 aliyun.club 当前最新2核4G服务器精准报价、优惠券和活动信息。 阿里云官方2…

leetCode刷题 18. 删除链表的倒数第 N 个结点

目录 1. 思路 2. 解题方法 3. 复杂度 4. Code 题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&…

IF= 13.4| 当eDNA遇上机器学习法

近日&#xff0c;凌恩生物客户重庆医科大学在《Water Research》&#xff08;IF 13.4&#xff09;发表研究论文“Supervised machine learning improves general applicability of eDNA metabarcoding for reservoir health monitoring”。该研究主要介绍了一种基于eDNA的机器学…

2023混合多比特层-RDHEI Based on the Mixed Multi-Bit Layer Embedding Strategy

RRBE 本文仅供自我学习记录,切勿转载和搬运,如有侵权联系立删! 方法总框架 首先,发送者将载体图像进行两轮的不重叠块分割,分为可用隐藏块(AHB)和不可用隐藏块(UHB),然后通过依次处理可用块的像素信息产生location图来创造空间,接着通过密钥将载体进行加密,最后使用…

怎样在NEXT.JS中设置next-auth并实现登入登出

参考代码link&#xff1a;https://github.com/luomi16/next-auth-demo 在Next.js中使用next-auth来实现登录和登出功能是一种流行且相对简单的方法。next-auth是一个专为Next.js开发的认证库&#xff0c;支持多种认证提供者&#xff0c;如Google、Facebook、Twitter以及基于邮…

档案四性检测可复用组件接口说明

nhdeep提供在归档、移交与接收、长期保存等各环节根据需求进行自主配置和调用的可复用组件&#xff0c;支持客户端和接口调用两种功能使用模式。档案四性检测组件为自建档案管理系统和各种业务系统&#xff08;如OA&#xff09;&#xff0c;提供标准化的档案四性检测功能利用&a…

【分享】CMMI V3.0版本做了哪些改变?哪些企业适合申请CMMI3.0

​ CMM是由美国卡内基梅隆大学软件工程研究所1987年开发成功的&#xff0c;它基于过去所有软件工程过程改进的成果&#xff0c;吸取了以往软件工程的经验教训&#xff0c;提供了一个基于过程改进的框架&#xff1b;CMMI(Capability Maturity Model Integration能力成熟度模型集…

esp单片机下arduino_gfx不相干显示驱动优化对flash空间的占用对比

一般情况下&#xff0c;很多esp32或者esp8266下的tft模块驱动都会包含很多种&#xff0c;而我们只需要其中一种&#xff0c;那就有个疑问这些被编译进的显示驱动到底占用了多少空间&#xff0c;是否需要把他优化掉&#xff1f; 这是默认的驱动列表&#xff1a; 84个文件&…

Android14之深入理解sp模板类(二百零二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

C语言例4-12:从键盘输入一个学生的学号、性别和一门课程的成绩后输出该学生的信息

代码如下&#xff1a; //从键盘输入一个学生的学号、性别和一门课程的成绩后输出该学生的信息 #include<stdio.h> int main(void) {int num; //定义整型变量num存放学生的学号char sex; //定义字符型变量sex存放学生的性别float score; //定义实型变量score存放学…

实现多线程方式你知道几种?

实现多线程通常有以下四种方式&#xff1a; 继承 Thread 类。实现 Runnable 接口。实现 Callable 接口。线程池实现多线程。 继承 Thread 类&#xff1a; public class ThreadDemo extends Thread{Overridepublic void run(){System.out.println("Thread 类实现多线程,…

现在的市场对 C++ 的需求大吗?

先说结论&#xff1a;需求还是很大&#xff0c;但是没有什么初级程序员能干的岗位。 游戏引擎&#xff0c;存储&#xff0c;推荐引擎&#xff0c;infra&#xff0c;各种各样的性能敏感场景。 在开始前我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;…

Linux系统服务

文章目录 什么是daemon与服务(service)systemd使用unit分类 通过systemctl管理服务通过systemctl管理单一服务(service unit)通过systemctl查看系统上所有的服务通过systemctl管理不同的操作环境(target unit)通过systemctl分析各服务之间的依赖性与systemd的daemon运行过程相关…

基于nodejs+vue铁路订票管理系统python-flask-django-php

该铁路订票管理系统采用前后端分离进行设计&#xff0c;并采用nodejs语言以及express框架进行开发。本系统主要设计并完成了用户登录管理过程、个人信息修改、用户管理、火车类型管理、火车信息管理、车票预订管理、车票退票管理、系统管理等功能。该系统操作简单&#xff0c;界…

考研数学|武忠祥高数全年学习包分享

u1s1&#xff0c;武忠祥老师的课程真的不错&#xff0c;宝藏级老师 其实我觉得没必要对比每一个考研数学老师&#xff0c;汤家凤还有张宇以及武忠祥都是非常受欢迎的老师&#xff0c;也都很有实力&#xff0c;只不过讲课的风格有所区别。 比如汤家凤老师就像是高中那种不苟言…

2024华为产业链企业名单大全(附下载)

更多内容&#xff0c;请前往知识星球下载&#xff1a;https://t.zsxq.com/18fsVdcjA 更多内容&#xff0c;请前往知识星球下载&#xff1a;https://t.zsxq.com/18fsVdcjA

mapbox测距功能重写

// 使用 import MeatureTool from "/components/webgisMap/measureTool";measureDistance() {// ID可以自定义const layerId String(new Date().getTime())this.meatureTool new MeatureTool(this.mapBoxMap)this.meatureTool.measureDistance(layerId)// 防止函数…

动态内存管理-传值调用错题解析

首先我们来看这个错误代码 首先我们看代码逻辑&#xff0c;首先main函数调用test&#xff0c;test接收的是void类型&#xff0c;设置一个指针变量&#xff0c;指向null&#xff0c;传递给get函数&#xff0c;也就是传递一个空指针给getmemory函数&#xff0c;这个函数接收了&a…