Flutter单页面能否实现两个从右侧滑出的End Drawer?
Flutter实现第二个右侧滑出抽屉的方案
Flutter的Scaffold默认仅支持一个左侧抽屉(drawer)和一个右侧抽屉(endDrawer),要实现第二个从右侧滑出的抽屉,需要自定义滑出逻辑,以下提供两种可行方案:
方案一:使用DrawerController控制额外Drawer
利用Flutter自带的DrawerController组件,直接管理第二个Drawer的显示状态,快速实现右侧滑出效果。
代码示例
import 'package:flutter/material.dart'; class DoubleEndDrawerPage extends StatefulWidget { const DoubleEndDrawerPage({super.key}); @override State<DoubleEndDrawerPage> createState() => _DoubleEndDrawerPageState(); } class _DoubleEndDrawerPageState extends State<DoubleEndDrawerPage> { final scaffoldKey = GlobalKey<ScaffoldState>(); // 第二个右侧抽屉的控制器Key final secondEndDrawerKey = GlobalKey<DrawerControllerState>(); @override Widget build(BuildContext context) { return Scaffold( key: scaffoldKey, appBar: AppBar( title: const Text("双右侧抽屉示例"), actions: [ IconButton( onPressed: () { scaffoldKey.currentState?.openEndDrawer(); }, icon: const Icon(Icons.filter_alt_outlined), ), ], ), // 第一个右侧抽屉 endDrawer: Drawer( child: Container( color: Colors.lightBlue.shade50, child: const Center(child: Text("第一个右侧抽屉")), ), ), body: Stack( children: [ // 原页面主体内容 Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: IconButton( icon: const Icon(Icons.sort, size: 32), onPressed: () { // 触发打开第二个右侧抽屉 secondEndDrawerKey.currentState?.open(); }, ), ), const Text("点击按钮打开第二个右侧抽屉"), ], ), // 第二个右侧抽屉 DrawerController( key: secondEndDrawerKey, // 设置抽屉从右侧滑出 alignment: Alignment.centerRight, child: Drawer( child: Container( width: MediaQuery.of(context).size.width * 0.7, color: Colors.orange.shade50, child: Column( children: [ AppBar( automaticallyImplyLeading: false, actions: [ IconButton( icon: const Icon(Icons.close), onPressed: () { secondEndDrawerKey.currentState?.close(); }, ), ], ), const Expanded(child: Center(child: Text("第二个右侧抽屉"))), ], ), ), ), ), ], ), ); } }
方案二:自定义SlideTransition实现滑出动画
如果需要更灵活的动画效果(比如调整动画时长、曲线),可以使用SlideTransition结合AnimationController实现自定义右侧滑出抽屉,还能自由添加遮罩层。
代码示例
import 'package:flutter/material.dart'; class CustomEndDrawerPage extends StatefulWidget { const CustomEndDrawerPage({super.key}); @override State<CustomEndDrawerPage> createState() => _CustomEndDrawerPageState(); } class _CustomEndDrawerPageState extends State<CustomEndDrawerPage> with SingleTickerProviderStateMixin { final scaffoldKey = GlobalKey<ScaffoldState>(); late AnimationController _animationController; late Animation<Offset> _slideAnimation; bool _isSecondDrawerOpen = false; @override void initState() { super.initState(); // 初始化动画控制器 _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); // 定义从右侧滑入的动画轨迹 _slideAnimation = Tween<Offset>( begin: const Offset(1, 0), // 初始状态在屏幕右侧外部 end: Offset.zero, // 滑入屏幕内的目标位置 ).animate(CurvedAnimation( parent: _animationController, curve: Curves.easeInOut, )); } // 打开第二个抽屉 void _openSecondDrawer() { setState(() => _isSecondDrawerOpen = true); _animationController.forward(); } // 关闭第二个抽屉 void _closeSecondDrawer() { _animationController.reverse().then((_) { setState(() => _isSecondDrawerOpen = false); }); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( key: scaffoldKey, appBar: AppBar( title: const Text("自定义右侧抽屉"), actions: [ IconButton( onPressed: () { scaffoldKey.currentState?.openEndDrawer(); }, icon: const Icon(Icons.filter_alt_outlined), ), ], ), endDrawer: Drawer( child: Container( color: Colors.lightBlue.shade50, child: const Center(child: Text("第一个右侧抽屉")), ), ), body: Stack( children: [ // 原页面主体内容 Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: IconButton( icon: const Icon(Icons.sort, size: 32), onPressed: _openSecondDrawer, ), ), const Text("点击按钮打开第二个右侧抽屉"), ], ), // 遮罩层:抽屉打开时点击空白处关闭 if (_isSecondDrawerOpen) GestureDetector( onTap: _closeSecondDrawer, child: Container( color: Colors.black54, width: double.infinity, height: double.infinity, ), ), // 第二个右侧抽屉 SlideTransition( position: _slideAnimation, child: Container( width: MediaQuery.of(context).size.width * 0.75, color: Colors.white, child: Column( children: [ AppBar( backgroundColor: Colors.orange.shade100, automaticallyImplyLeading: false, actions: [ IconButton( icon: const Icon(Icons.close), onPressed: _closeSecondDrawer, ), ], title: const Text("第二个抽屉"), ), const Expanded(child: Center(child: Text("自定义动画的右侧抽屉"))), ], ), ), ), ], ), ); } }
内容的提问来源于stack exchange,提问作者Leong
相关产品推荐
相关产品推荐

