flutter实现一个列表下拉抽屉的示例代码

目录
  • 使用
  • 源码

使用

通过监听滚动事件实现DragOpenDrawer 组件,可以给滚动组件添加一个下拉抽屉。其使用方式如下:

DragOpenDrawer(
  openDuration: Duration(microseconds: 900),
  closeDuration: Duration(milliseconds: 300),
  onOpen: (){
    print("onOpen");
  },
 child: Column(
      children: [
        Expanded(
          child: ListView.builder(
              itemCount: 40,
              itemBuilder: (context,index){
            return ListTile(title: Text("$index"),);
          }),
        ),
      ]
    ),
  backgroundBuilder: (context){
    return Container(child: FlutterLogo(style: FlutterLogoStyle.stacked,),color: Colors.blue[200],);
  },
),

组件参数说明

  • openDuration:抽屉打开动画持续的时间
  • closeDuration: 抽屉关闭动画持续的时间
  • onOpen: 抽屉打开事件回调
  • child: DragOpenDrawer 组件监听的滚动组件
  • backgroundBuilder:抽屉打开后展示的组件

运行效果

源码

import 'package:flutter/material.dart';

enum _DragOpenDrawerMode{
  // 正在拖动
  dragging,
  // 抽同打开事件已经触发
  done,
  // 抽屉处于关闭状态
  canceled,
  // 抽屉已经打开了
  opened,
}

class DragOpenDrawer extends StatefulWidget {
  const DragOpenDrawer({
    required this.child,
    required this.backgroundBuilder,
    this.onOpen,
    this.openDuration =  const Duration(seconds: 1),
    this.closeDuration = const Duration(seconds: 1),
    Key? key}) : super(key: key);

  final Widget Function(BuildContext context) backgroundBuilder;
  final Widget  child;

  /// 抽屉打开时的回调函数
  final void Function()? onOpen;

  final Duration openDuration;
  final Duration closeDuration;

  @override
  _DragOpenDrawerState createState() => _DragOpenDrawerState();
}

class _DragOpenDrawerState extends State<DragOpenDrawer> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late double _maxHeight;
  double _dragOffset = .0;
  bool _openTriggered = false;
  _DragOpenDrawerMode _dragOpenDrawerMode = _DragOpenDrawerMode.canceled;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }

  @override
  void dispose() {
    _changeDragOpenDrawerMode(_DragOpenDrawerMode.canceled);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        _maxHeight = constraints.maxHeight;
        return  WillPopScope(
          onWillPop: () async{
            if(_dragOpenDrawerMode == _DragOpenDrawerMode.opened){
              _changeDragOpenDrawerMode(_DragOpenDrawerMode.canceled);
              return false;
            }
            return true;
          },
          child: Stack(
            alignment: Alignment.topCenter,
            children: [
              SizedBox(
                width: double.infinity,
                height: double.infinity,
                child: ScaleTransition(
                    alignment: Alignment.topCenter,
                    scale: _controller,
                    child: widget.backgroundBuilder(context)),
              ),
              AnimatedBuilder(
                animation: _controller,
                builder: (BuildContext context, Widget? child) {
                  return  Positioned(
                    top: Tween(begin: .0, end: _maxHeight).evaluate(_controller),
                    height: _maxHeight,
                    width: constraints.maxWidth,
                    child: NotificationListener(
                        onNotification: (notification){
                          if(notification is OverscrollNotification){
                            if(notification.overscroll >= 0){
                              return true;
                            }else{
                              _dragOffset -= notification.overscroll;

                              _changeDragOpenDrawerMode(_DragOpenDrawerMode.dragging);

                              if(_dragOffset >_maxHeight/4){
                                _changeDragOpenDrawerMode(_DragOpenDrawerMode.done);
                              }
                            }
                          }else if(notification is ScrollEndNotification && _dragOpenDrawerMode != _DragOpenDrawerMode.done){
                            _controller
                              ..duration = widget.closeDuration
                              ..reverse().then((value) => _dragOffset = .0);
                          }else if(notification is ScrollEndNotification && _dragOpenDrawerMode == _DragOpenDrawerMode.done){
                            _changeDragOpenDrawerMode(_DragOpenDrawerMode.opened);
                          }
                          return true;
                        },
                        child: child ?? SizedBox()),
                  );
                },
                child:Container(
                  color: Colors.white,
                  height: _maxHeight,
                  child: widget.child
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  _changeDragOpenDrawerMode(_DragOpenDrawerMode newMode)async{
    _dragOpenDrawerMode = newMode;

    switch (newMode){
      case _DragOpenDrawerMode.canceled : {
        _controller.duration = widget.closeDuration;
        await _controller.reverse();
        _openTriggered = false;
        _dragOffset = .0;
        break;
      }

      case _DragOpenDrawerMode.dragging:
        _controller.duration = Duration(seconds: 0);
        await  _controller.animateTo(_dragOffset/_maxHeight);
        break;

      case _DragOpenDrawerMode.opened:
        _controller.duration = widget.openDuration;
        await _controller.forward();
        break;

      case _DragOpenDrawerMode.done:
        if(!_openTriggered){
          widget.onOpen!.call();
        }
        _openTriggered = true;
        break;
      default:
        //executeUnknown();
    }
  }
}

到此这篇关于flutter实现一个列表下拉抽屉的示例代码的文章就介绍到这了,更多相关flutter 列表下拉抽屉内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Flutter Drawer实现抽屉菜单效果

    本文实例为大家分享了Flutter Drawer实现抽屉菜单的具体代码,供大家参考,具体内容如下 import 'package:flutter/material.dart'; void main() {   runApp(MyApp()); } class MyApp extends StatelessWidget {   @override   Widget build(BuildContext context) {     return MaterialApp(       debugSh

  • Flutter中抽屉组件Drawer使用详解

    本文实例为大家分享了Flutter中抽屉组件Drawer实现代码,供大家参考,具体内容如下 1.概述 Scalfold 是 Flutter MaterialApp 常用的布局 Widget,接受一个 drawer属性,支持配置 Drawer,可以实现从侧边栏拉出导航面板,好处是把一些功能菜单折叠起来,通常Drawer是和Listview组件或者 Column组合使用进行纵向布局.Listview组件是竖排排列的,上下可滑动. [注意]如果没有设置 AppBar 的 leading 属性,则当使用

  • Flutter Drawer抽屉菜单示例详解

    本文实例为大家分享了Flutter Drawer抽屉菜单示例代码,供大家参考,具体内容如下 一.Flutter Drawer组件简介 1.源码查看 const Drawer({     Key? key,     this.elevation = 16.0, //阴影效果大小     this.child, //内容元素     this.semanticLabel, //关闭/打开抽屉时的通知信息   })  二.抽屉菜单示例 1.菜单项,使用 ListTile 实现 Expanded(  

  • flutter实现底部抽屉效果

    本文实例为大家分享了flutter实现底部抽屉效果的具体代码,供大家参考,具体内容如下 安卓:showModalBottomSheetIOS:showCupertinoModalPopup 效果图 完整代码 import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; ///@作者: Q.L ///@创建日期: 2021-09-09 10:55 ///@描述: {底部抽屉} class Actio

  • flutter实现一个列表下拉抽屉的示例代码

    目录 使用 源码 使用 通过监听滚动事件实现DragOpenDrawer 组件,可以给滚动组件添加一个下拉抽屉.其使用方式如下: DragOpenDrawer(   openDuration: Duration(microseconds: 900),   closeDuration: Duration(milliseconds: 300),   onOpen: (){     print("onOpen");   },  child: Column(       children: [

  • Android Scroll实现弹性滑动_列表下拉弹性滑动的示例代码

    我这一次讲使用scroll实现弹性滑动,我不会只有一个例子就说完,因为写文章的时候我也在学习,我分几次讲完吧. 首先上一段代码, private void smoothScrollByScroller(int dy){ mScroller.startScroll(0,dy,0,dy*-1,1000); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scr

  • 在Angular中实现一个级联效果的下拉框的示例代码

    实现一个具有级联效果的下拉搜索框,实现的结果如下图所示 我们主要通过这个组件,来学习一些细微的逻辑,比如: 如何计算input框内文字的长度: 如何获取光标的位置:如何实现滚动条随着上下键盘的按动进行移动...... 具体需求如下 级联搜索最多不超过三级,以"."作为级联搜索的连接符 搜索框跟着文本框中的"."进行向后移动,向右移动的最大距离不能超过文本框的宽度 当用户修改之前的级联内容,则不进行搜索,并隐藏搜索框:若用户在之前输入的是".",

  • Android实现简单的下拉阻尼效应示例代码

    OS的下拉上拉都会出现一个很玄的动态效果.在Android中,虽然可以实现类似的效果,但有点不同的是,如果调用overScrollBy来实现类似的阻尼效应的话,最顶部会出现一片亮的区域,让人感觉不是很爽.所以决定不采用该方法来实现而是改用自定义的方式来实现. 下面是自定义控件的代码部分: public class MyView extends ScrollView { //记录下最开始点击的位置 int initY; //移动的位置 int deltaY; int touchY; //记录第一个

  • 微信小程序实现触底加载与下拉刷新的示例代码

    目录 触底加载 loader函数思考 loader函数实现 触底加载动画 触底加载的优点 下拉刷新 最后 在最近做小程序的时候有这么一个很常见的需求,加载一个信息列表,要求需要触底加载和下拉刷新,我突然想起来掘金小册界面和这个需求很相似,接下来我给大家介绍一下我的实现方案. 触底加载 步骤如下: 封装一个loader函数 在监听页面加载的时候触发这个loader函数 在监听到触底的时候再次触发这个函数 onLoad: function (options) { this.loadBooks(thi

  • Vue+ElementUI实现从后台动态填充下拉框的示例代码

    1.首先编写前端代码,将elementUI中的标签写到.vue界面中.  <el-select       v-model="xxxQuery.xxxid"       placeholder="请在下拉框中选择名称"       maxlength="255"       :disabled="false"       clearable>             <el-option          

  • iview实现select tree树形下拉框的示例代码

    本文介绍了iview实现select tree树形下拉框的示例代码,分享给大家,具体如下: html部分 <Tree :data="treeData" ref="tree" :render="renderContent"></Tree> 数据部分 export const treeData= [ { title: 'parent 1', expand: true, selected: true, value: '1', c

  • Java实现级联下拉结构的示例代码

    目录 前言 构建统一返回下拉结构 构建集合<对象>转下拉树工具类 构建List<Map>转下拉或下拉树的工具类 前言 在开发过程中,会遇到很多的实体需要将查出的数据处理为下拉或者级联下拉的结构,提供给前端进行展示. 在数据库查出的结构中,可能是集合<实体类>的结构,也有可能是List<Map>的结构. 在下拉或者级联下拉的节点数据中,有时候还需要动态的携带其他的参数,已便于前端对某些数据的显示 如区域的级联下拉树中,需要携带经纬度的区域–在选择的时候在地图展

  • react实现移动端下拉菜单的示例代码

    前言 项目中要实现类似与vant的DropdownMenu:下拉菜单.看了vans 的效果 其实也没什么难度,于是动手鲁了一个这样的组件. 项目的技术栈为react全家桶+material UI + ant Design mobile. vans的效果 我自己实现的效果 思路 常规做法获取dom元素,动态修改选中dom的innerHtml. 当然这种方式不是react推荐的 我的做法既然react不推荐直接操作dom元素,那可以采用动态动态修改class的方式达到效果,例如: let cls =

  • vue基于vant实现上拉加载下拉刷新的示例代码

    前言 普遍存在于各种app中的上拉加载下拉刷新功能大家都不陌生吧,一般来说,在数据量比较大的情况下,为了更快的渲染和给用户更好的观感体验,我们会将数据做分页处理,让其批量加载,这样一来,在渲染速度上,能给用户一个比较好的体验效果.话说回来,分页处理,也就是我们今天要讲的上拉加载和下拉刷新. 实现思路 下拉刷新: 请求接口赋完值后,将接口返回数据长度与总条数进行比较控制加载不加载的状态,在下拉刷新方法中定义起始页码为第一页,调整加载的状态为false,最后调用请求数据的接口方法,做适当轻提示即可.

随机推荐