如何在 Flutter 中实现可拖动的底部弹出框

devtools/2024/9/29 23:56:29/

在 Flutter 开发中,底部弹出框(Bottom Sheet)是一种常见的 UI 组件,通常用于显示一些额外的操作选项或详细信息。在这篇文章中,我将介绍一个自定义的 DragBottomSheetWidget 组件,它不仅支持手势拖动关闭,还可以通过动画进行弹出和收起。

组件功能概述

DragBottomSheetWidget 是一个支持手势拖动和动画效果的底部弹出框组件。它具有以下几个主要功能:

  1. 手势下拉关闭:用户可以通过向下拖动来关闭底部弹出框。
  2. 动画弹出收起:支持平滑的动画效果,弹出或收起时更加自然。
  3. 弹出后无法关闭:在特定场景下,弹出框可以设置为无法通过手势关闭。
代码解析

首先,我们来看一下 DragBottomSheetWidget 的代码实现:

import 'package:flutter/material.dart';class DragBottomSheetWidget extends StatefulWidget {const DragBottomSheetWidget({super.key,required this.builder,this.duration = const Duration(milliseconds: 200),this.childHeightRatio = 0.8,this.onStateChange,});final Function(bool)? onStateChange;final double childHeightRatio;final Duration duration;final ScrollableWidgetBuilder builder;State<DragBottomSheetWidget> createState() => DragBottomSheetWidgetState();
}class DragBottomSheetWidgetState extends State<DragBottomSheetWidget> {final DraggableScrollableController controller =DraggableScrollableController();final ValueNotifier<bool> isExpandNotifier = ValueNotifier<bool>(false);double verticalDistance = 0;void initState() {super.initState();}void dispose() {controller.dispose();isExpandNotifier.dispose();super.dispose();}Future<void> show({bool isCanClose = true}) async {try {await controller.animateTo(1,duration: widget.duration,curve: Curves.linear,);if (!isCanClose) {isExpandNotifier.value = true;}} catch (e) {print('Error animating to full size: $e');}}void hide() {controller.animateTo(0,duration: widget.duration,curve: Curves.linear,);}void _dragJumpTo(double y) {final size = y / MediaQuery.sizeOf(context).height;final jumpToValue = widget.childHeightRatio - size;controller.jumpTo(jumpToValue.clamp(0, widget.childHeightRatio));}void _dragEndChange(DragEndDetails dragEndDetails) {if (controller.size >= widget.childHeightRatio / 2) {controller.animateTo(1,duration: widget.duration,curve: Curves.linear,);} else {hide();}}Widget build(BuildContext context) {return NotificationListener<DraggableScrollableNotification>(onNotification: (notification) {isExpandNotifier.value = notification.extent == widget.childHeightRatio;widget.onStateChange?.call(isExpandNotifier.value);return true;},child: ValueListenableBuilder<bool>(valueListenable: isExpandNotifier,builder: (context, isExpand, child) {return DraggableScrollableSheet(initialChildSize: !isExpand ? 0 : widget.childHeightRatio,minChildSize: 0,maxChildSize: widget.childHeightRatio,expand: true,snap: true,controller: controller,builder: (BuildContext context, ScrollController scrollController) {return _DragHandler(onDragDown: () => verticalDistance = 0,onDragUpdate: (details) {verticalDistance += details.delta.dy;_dragJumpTo(verticalDistance);},onDragEnd: _dragEndChange,child: widget.builder(context, scrollController),);},);},),);}
}class _DragHandler extends StatelessWidget {const _DragHandler({required this.onDragDown,required this.onDragUpdate,required this.onDragEnd,required this.child,});final VoidCallback onDragDown;final GestureDragUpdateCallback onDragUpdate;final GestureDragEndCallback onDragEnd;final Widget child;Widget build(BuildContext context) {return GestureDetector(behavior: HitTestBehavior.translucent,onVerticalDragDown: (_) => onDragDown(),onVerticalDragUpdate: onDragUpdate,onVerticalDragEnd: onDragEnd,child: child,);}
}
核心功能解读
  1. 控制器与状态管理:组件内部使用了 DraggableScrollableController 来控制弹出框的显示状态,ValueNotifier<bool> 用于监听弹出框的展开与收起状态。

  2. 显示与隐藏show 方法通过 animateTo 将弹出框平滑展开至全屏,而 hide 方法则将其收起至不可见状态。

  3. 手势控制:通过 _dragJumpTo 方法和 _dragEndChange 方法,组件可以响应用户的手势操作,决定弹出框的滑动与状态变化。

  4. Builder 模式:通过 builder 回调,开发者可以自定义弹出框中的内容,满足不同场景的需求。

使用场景

DragBottomSheetWidget 适用于需要在屏幕底部弹出一些交互式内容的场景,如表单输入、操作选项等。通过手势控制和动画效果,可以为用户提供更加流畅和直观的操作体验。

结语

自定义 DragBottomSheetWidget 组件不仅增强了 Flutter 的弹出框功能,还为用户提供了更多的交互可能性。如果你正在开发需要底部弹出框的应用,不妨尝试一下这个组件,为你的应用添加更丰富的交互体验。


http://www.ppmy.cn/devtools/118957.html

相关文章

@overload实际并无作用

overload 装饰器在 Python 中确实有些特殊。 虽然它看起来像是实现了函数重载&#xff0c;但实际上并没有真正改变函数的行为。 overload 主要用于类型提示和提高代码的可读性。 在 Python 中&#xff0c;函数重载&#xff08;即根据参数类型或数量调用不同的函数实现&#xf…

C++【类和对象】(取地址运算符重载与实现Date类)

文章目录 取地址运算符重载const成员函数取地址运算符重载 Date类的实现Date.hDate.cpp1.检查日期合法性2. 构造函数/赋值运算符重载3.得到某月的天数4. Date类 - 天数的操作4.1 日期 天数4.2 日期 天数4.3 日期 - 天数4.4 日期 - 天数 5. Date的前后置/--5.1 前置5.2 后置5.…

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库 一、环境说明二、分布式键值数据库介绍三、示例代码加以说明四、小结 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、分布式键值数据库介绍 KVStore简介&#xff1a; 分布式键值数据库…

图为科技大模型一体机,智领未来社区服务

当AI与边缘计算相遇&#xff0c;一幅关于智慧生活的宏伟蓝图正缓缓展开。 今天&#xff0c;让我们一同探索&#xff0c;如何通过图为大模型一体机&#xff0c;为物业服务插上智能的翅膀。 通过整合采集物业数据&#xff0c;大模型一体机可全方位为物业行业赋能&#xff0c;实…

docker - maven 插件自动构建镜像(构建镜像:ebuy-docker:v2.0)

文章目录 1、docker服务端开启远程访问2、在pom.xml文件plugins下添加Maven的docker插件3、编写dockerfile文件4、执行maven的打包命令5、查看 镜像 ebuy-docker:v2.06、创建 容器 ebuy-dockerv2.0 上面手动构建镜像的过程比较繁琐&#xff0c;使用Maven的docker插件可以实现镜…

Java 之 ssm框架入门

SSM框架作为Java Web开发的热门选择&#xff0c;其强大功能和易用性吸引了众多开发者。以下是我对该框架的理解以及学习建议&#xff0c;仅供参考 一、 SSM框架深度解析 1. Spring 核心技术 IoC (控制反转) 概念: 将对象的创建和管理权利交给Spring容器&#xff0c;通过依赖注…

OpenCV图像文件读写(2) 检查 OpenCV 是否支持某种图像格式的写入功能函数haveImageWriter()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 haveImageWriter 函数用于检查 OpenCV 是否支持某种图像格式的写入功能。这个函数可以帮助开发者在编写代码时确定是否可以成功地将图像写入特定…

【Java】内部类【主线学习笔记】

文章目录 前言内部类内部类的使用举例内部类的分类对于成员内部类的理解 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台性和高效的执行速度&#xff0c;广受开发者喜爱。在接下来的学习过程中&#xff0c;我将记录学习过程中的基础语法、框架和实践技巧等…