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 列表下拉抽屜內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解Flutter中數據傳遞的方式
- Flutter折疊控件使用方法詳解
- Flutter給控件實現鉆石般的微光特效
- Flutter Component動畫的顯和隱最佳實踐
- Flutter瀑佈流仿寫原生的復用機制詳解