Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > flutter 列表下拉抽屉

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

作者:BubbleSlayer

本文主要介绍了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],);
  },
),

组件参数说明

运行效果

源码

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 列表下拉抽屉内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文