Flutter抽屉ExpansionTile展开时底部溢出3像素问题求解
修复Flutter抽屉展开ExpansionTile时的底部溢出问题
问题原因
当前Drawer内部用Column布局,展开ExpansionTile后,总内容高度超过了Drawer的可用视口高度,而Column不支持滚动,因此触发“bottom overflowed by 3 pixels”的溢出提示。
解决方案
下面提供两种可行方案,按需选择:
方案1:保留底部固定的Logout按钮(推荐)
通过Expanded + SingleChildScrollView包裹中间的列表内容,让这部分支持滚动,同时让Logout按钮固定在抽屉底部。
修改后的完整代码:
return Scaffold( appBar: AppBar( backgroundColor: Color(0xFF781B1B), foregroundColor: Colors.white, title: Text(widget.page), ), body: PageBody(widget.page), drawer: SafeArea( child: Container( width: 250, child: Drawer( backgroundColor: Theme.of(context).colorScheme.onPrimary, child: Column( children: <Widget>[ DrawerHeader( padding: EdgeInsets.zero, child: UserAccountsDrawerHeader( accountName: Text( name, style: TextStyle( color: Colors.white, fontSize: 18.0, ), ), accountEmail: null, currentAccountPicture: CircleAvatar( backgroundColor: Colors.white, child: Icon( Icons.person, color: Color(0xFF781B1B), size: 48.0, ), ), decoration: BoxDecoration( color: Color(0xFF781B1B), ), ), ), // 用Expanded让滚动区域占满头部和底部之间的空间 Expanded( child: SingleChildScrollView( child: Column( children: <Widget>[ ListTile( leading: const Icon(Icons.account_box), title: const Text('Profile'), selected: _selectedIndex == 0, onTap: () { if (_selectedIndex == 0) return; GoRouter.of(context).pop(); GoRouter.of(context).push("/show_profile"); setState(() { _selectedIndex = 0; }); }, ), ExpansionTile( leading: Icon(Icons.confirmation_num), title: Text('Tickets'), initiallyExpanded: _selectedIndex == 1, onExpansionChanged: (bool expanded) { if (expanded) { setState(() { _selectedIndex = 1; }); } }, children: <Widget>[ ListTile( leading: Icon(Icons.confirmation_num), title: Text('Choose Ticket'), onTap: () { GoRouter.of(context).pop(); GoRouter.of(context).push("/ticket_choose"); }, ), ListTile( leading: Icon(Icons.history), title: Text('Ticket History'), onTap: () { GoRouter.of(context).pop(); GoRouter.of(context).push("/ticket_history"); }, ), ], ), ListTile( leading: const Icon(Icons.mail), title: const Text('Requisition'), selected: _selectedIndex == 7, onTap: () { if (_selectedIndex == 7) return; GoRouter.of(context).pop(); GoRouter.of(context).push("/user_requisition"); setState(() { _selectedIndex = 7; }); }, ), ListTile( leading: const Icon(Icons.history), title: const Text('Show Requisition'), selected: _selectedIndex == 8, onTap: () { if (_selectedIndex == 8) return; GoRouter.of(context).pop(); GoRouter.of(context).push("/show_requisition"); setState(() { _selectedIndex = 8; }); }, ), ], ), ), ), // 直接放置Logout按钮,固定在底部 ListTile( visualDensity: const VisualDensity(vertical: 4), leading: const Icon(Icons.logout), title: const Text('Log out'), selected: false, onTap: () async { var r1 = await Requests.post( 'http://18.117.93.134:6969/api/logout'); r1.raiseForStatus(); dynamic json1 = r1.json(); if (json1['success']) { await Requests.clearStoredCookies( "18.117.93.134:6969"); Fluttertoast.showToast( msg: 'Logged out.', toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Color.fromARGB(73, 77, 65, 64), textColor: Colors.white, fontSize: 16.0); GoRouter.of(context).go("/login"); } }, ), ], ), ), ), ), );
方案2:让所有内容随滚动移动
如果不需要Logout按钮固定在底部,直接把Column替换成ListView,利用ListView的滚动特性解决溢出问题:
核心修改部分:
drawer: SafeArea( child: Container( width: 250, child: Drawer( backgroundColor: Theme.of(context).colorScheme.onPrimary, child: ListView( padding: EdgeInsets.zero, children: <Widget>[ DrawerHeader(...), // 原代码不变 ListTile(...), // Profile项 ExpansionTile(...), // Tickets项 ListTile(...), // Requisition项 ListTile(...), // Show Requisition项 // 可选:添加间距让Logout靠底部 SizedBox(height: MediaQuery.of(context).size.height - 600), ListTile(...), // Logout项 ], ), ), ), ),
说明
- 方案1既保留了底部固定的Logout按钮,又让中间内容支持滚动,更符合大多数场景的需求。
- 方案2实现简单,但Logout按钮会随内容滚动,适合不需要固定底部的场景。
内容的提问来源于stack exchange,提问作者Nafiu Rahman
相关产品推荐
相关产品推荐

