flutter實(shí)現(xiàn)一個(gè)列表下拉抽屜的示例代碼
使用
通過(guò)監(jiān)聽(tīng)滾動(dòng)事件實(shí)現(xiàn)DragOpenDrawer 組件,可以給滾動(dòng)組件添加一個(gè)下拉抽屜。其使用方式如下:
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],); ? }, ),
組件參數(shù)說(shuō)明
- openDuration:抽屜打開動(dòng)畫持續(xù)的時(shí)間
- closeDuration: 抽屜關(guān)閉動(dòng)畫持續(xù)的時(shí)間
- onOpen: 抽屜打開事件回調(diào)
- child: DragOpenDrawer 組件監(jiān)聽(tīng)的滾動(dòng)組件
- backgroundBuilder:抽屜打開后展示的組件
運(yùn)行效果
源碼
import 'package:flutter/material.dart'; enum _DragOpenDrawerMode{ ? // 正在拖動(dòng) ? dragging, ? // 抽同打開事件已經(jīng)觸發(fā) ? done, ? // 抽屜處于關(guān)閉狀態(tài) ? canceled, ? // 抽屜已經(jīng)打開了 ? 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; ? /// 抽屜打開時(shí)的回調(diào)函數(shù) ? 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(); ? ? } ? } }
到此這篇關(guān)于flutter實(shí)現(xiàn)一個(gè)列表下拉抽屜的示例代碼的文章就介紹到這了,更多相關(guān)flutter 列表下拉抽屜內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android監(jiān)聽(tīng)手機(jī)電話狀態(tài)與發(fā)送郵件通知來(lái)電號(hào)碼的方法(基于PhoneStateListene實(shí)現(xiàn))
這篇文章主要介紹了Android監(jiān)聽(tīng)手機(jī)電話狀態(tài)與發(fā)送郵件通知來(lái)電號(hào)碼的方法,通過(guò)Android的PhoneStateListene實(shí)現(xiàn)該功能,需要的朋友可以參考下2016-01-01解決webview內(nèi)的iframe中的事件不可用的問(wèn)題
這篇文章主要介紹了解決webview內(nèi)的iframe中的事件不可用的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Google 開發(fā)Android MVP架構(gòu)Demo深入解析
這篇文章主要為大家介紹了Google 開發(fā)Android MVP架構(gòu)Demo深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Flutter基于Dart Unwrapping Multiple Optional小技巧
這篇文章主要為大家介紹了Flutter Unwrapping Multiple Optional打開多個(gè)選項(xiàng)小技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android 利用廣播監(jiān)聽(tīng)usb連接狀態(tài)(變化情況)
這篇文章主要介紹了Android 利用廣播監(jiān)聽(tīng)usb連接狀態(tài),需要的朋友可以參考下2017-06-06Android與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本
這篇文章主要為大家介紹了安卓與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android自定義View系列之Path繪制仿支付寶支付成功動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android自定義View系列之Path繪制仿支付寶支付成功動(dòng)畫,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12