flutter實(shí)現(xiàn)一個(gè)列表下拉抽屜的示例代碼
使用
通過監(jiān)聽滾動(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ù)說明
- openDuration:抽屜打開動(dòng)畫持續(xù)的時(shí)間
- closeDuration: 抽屜關(guān)閉動(dòng)畫持續(xù)的時(shí)間
- onOpen: 抽屜打開事件回調(diào)
- child: DragOpenDrawer 組件監(jiān)聽的滾動(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 App更改應(yīng)用的圖標(biāo)的實(shí)現(xiàn)方法
這篇文章主要介紹了Android App更改應(yīng)用的圖標(biāo)的實(shí)現(xiàn)方法的相關(guān)資料,主要是通過入口Activity android:icon="@drawable/new_app_icon" 指向新的應(yīng)用圖標(biāo),需要的朋友可以參考下2017-08-08
Android創(chuàng)建和使用數(shù)據(jù)庫SQLIte
這篇文章主要為大家詳細(xì)介紹了Android創(chuàng)建和使用數(shù)據(jù)庫SQLIte的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05
Android編程使用自定義shape實(shí)現(xiàn)shadow陰影效果的方法
這篇文章主要介紹了Android編程使用自定義shape實(shí)現(xiàn)shadow陰影效果的方法,涉及Android中xml文件布局的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
android自定義環(huán)形統(tǒng)計(jì)圖動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了android自定義環(huán)形統(tǒng)計(jì)圖動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07
實(shí)例講解Android應(yīng)用開發(fā)中Fragment生命周期的控制
這篇文章主要介紹了Android應(yīng)用開發(fā)中Fragment生命周期的控制,Fragment依賴于Activity,所以生命周期方面也受Activity的影響,需要的朋友可以參考下2016-02-02
Android實(shí)現(xiàn)漂亮的Gallery畫廊
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)漂亮的Gallery畫廊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
Android Studio屏幕方向以及UI界面狀態(tài)的保存代碼詳解
在本篇文章里小編給各位整理的是關(guān)于Android Studio屏幕方向以及UI界面狀態(tài)的保存代碼以及相關(guān)知識(shí)點(diǎn),需要的跟著學(xué)習(xí)下。2019-10-10

