如何让抽屉推动内容而不是放在上面?
Posted
技术标签:
【中文标题】如何让抽屉推动内容而不是放在上面?【英文标题】:How to have the drawer push the content instead of going on top of it? 【发布时间】:2021-06-11 19:37:24 【问题描述】:我正在尝试构建类似于 slack 应用程序(见下面的屏幕截图)的东西,其中导航抽屉将屏幕推开而不是放在顶部。
我一直在尝试使用 Drawer
组件,但没有成功。我也看过PageView
,但似乎孩子们需要占用 100% 的宽度。
有人知道如何实现它吗?
【问题讨论】:
scaffolds openDrawer 使用导航器,您可以使用带有Scrollable.ensureVisible(context)
的单子水平滚动视图(禁用滚动物理)来显示菜单
【参考方案1】:
编辑
使用Stack
和AnimatedPositioned
可以获得类似的结果
class SlidingDrawer extends StatefulWidget
final Widget drawer;
final Widget child;
final int swipeSensitivity;
final double drawerRatio;
final Color overlayColor;
final double overlayOpacity;
final int animationDuration;
final Curve animationCurve;
SlidingDrawer(
Key key,
@required this.drawer,
@required this.child,
this.swipeSensitivity = 25,
this.drawerRatio = 0.8,
this.overlayColor = Colors.black,
this.overlayOpacity = 0.5,
this.animationDuration = 500,
this.animationCurve = Curves.ease,
) : super(key: key);
@override
_SlidingDrawerState createState() => _SlidingDrawerState();
class _SlidingDrawerState extends State<SlidingDrawer>
bool _opened = false;
void open()
setState(()
_opened = true;
);
void close()
setState(()
_opened = false;
);
@override
Widget build(BuildContext context)
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final drawerWidth = width * widget.drawerRatio;
return GestureDetector(
onHorizontalDragUpdate: (details)
if (details.delta.dx > widget.swipeSensitivity)
open();
else if (details.delta.dx < -widget.swipeSensitivity)
close();
,
child: SizedBox(
width: width,
height: height,
child: Stack(
children: [
AnimatedPositioned(
width: drawerWidth,
height: height,
left: _opened ? 0 : -drawerWidth,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Container(
color: Colors.amber,
child: widget.drawer,
),
),
AnimatedPositioned(
height: height,
width: width,
left: _opened ? drawerWidth : 0,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Stack(
fit: StackFit.expand,
children: [
widget.child,
AnimatedSwitcher(
duration: Duration(milliseconds: widget.animationDuration),
switchInCurve: widget.animationCurve,
switchOutCurve: widget.animationCurve,
child: _opened
? GestureDetector(
onTap: ()
setState(()
_opened = false;
);
,
child: Container(
color: widget.overlayColor.withOpacity(
widget.overlayOpacity,
),
),
)
: null,
)
],
),
),
],
),
),
);
原始答案
正如@Yadu 在评论中指出的那样
您可以使用带有 Scrollable.ensureVisible(context) 的单子水平滚动视图(禁用滚动物理)来显示菜单
使用水平滚动视图是有效的。
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
bool _drawerOpened = false;
final drawerKey = new GlobalKey();
final mainKey = new GlobalKey();
@override
Widget build(BuildContext context)
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
key: drawerKey,
color: Colors.green,
width: MediaQuery.of(context).size.width * 0.8,
),
SizedBox(
key: mainKey,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Scaffold(
appBar: AppBar(
title: Text("My Page"),
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: _toggleDrawer,
),
),
body: Container(
color: Colors.yellow,
width: MediaQuery.of(context).size.width,
),
),
),
],
),
);
void _toggleDrawer()
setState(()
_drawerOpened = !_drawerOpened;
);
if (_drawerOpened)
Scrollable.ensureVisible(drawerKey.currentContext);
else
Scrollable.ensureVisible(mainKey.currentContext);
【讨论】:
以上是关于如何让抽屉推动内容而不是放在上面?的主要内容,如果未能解决你的问题,请参考以下文章
单击抽屉的任何项目而不在android中关闭时更改导航抽屉内的视图和内容