【发布时间】:2020-01-04 23:21:15
【问题描述】:
我想以编程方式打开Drawer,而不是通过滑动它,如何禁用该滑动功能(抽屉的触摸功能)
【问题讨论】:
-
您希望它可以通过滑动访问吗?
-
不,我想禁用触摸滑动,我只想以编程方式打开它
标签: flutter dart flutter-layout
我想以编程方式打开Drawer,而不是通过滑动它,如何禁用该滑动功能(抽屉的触摸功能)
【问题讨论】:
标签: flutter dart flutter-layout
使用GlobalKey:
final GlobalKey<ScaffoldState> _key = GlobalKey(); // Create a key
@override
Widget build(BuildContext context) {
return Scaffold(
key: _key, // Assign the key to Scaffold.
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () => _key.currentState!.openDrawer(), // <-- Opens drawer
),
);
}
使用Builder:
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
floatingActionButton: Builder(builder: (context) {
return FloatingActionButton(
onPressed: () => Scaffold.of(context).openDrawer(), // <-- Opens drawer.
);
}),
);
}
如果你想禁止使用拖动手势打开Drawer,你可以设置
Scaffold(
drawerEnableOpenDragGesture: false
// above code ...
)
【讨论】:
drawerEnableOpenDragGesture 设置为 false。
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(
home: Scaffold(
// this to prevent the default sliding behaviour
drawerEnableOpenDragGesture: false,
drawer: Drawer(),
appBar: AppBar(
leading: Builder(builder: (context) => // Ensure Scaffold is in context
IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer()
),
),
)
)
);
}
}
要使用Scaffold.of(context) 以编程方式打开抽屉,您必须确保(感谢Krolaw!)调用所在的上下文知道脚手架。
一种简洁的方法是将按钮包装在构建器中。 我已经编辑了答案以包含一个最小的完整工作示例。
Scaffold 是一个实现材料设计原则的小部件,因此请注意,要能够调用此方法,您需要 import 'package:flutter/material.dart'; 并且您的小部件需要有一个 MaterialApp 作为祖先。
与许多 Flutter 事物一样,还有其他解决方案可以确保 Scaffold 在上下文中。
错误消息是 IMO 中 Flutter 框架的最佳功能之一,请允许我谦虚地建议始终通读它们并探索它们指向的文档。
例如,如果在适当的上下文之外调用 openDrawer,这是错误消息的一部分:
使用不包含 Scaffold 的上下文调用 Scaffold.of()。
从传递给 Scaffold.of() 的上下文开始,找不到任何 Scaffold 祖先。这通常发生在提供的上下文来自与其构建函数实际创建正在寻找的 Scaffold 小部件相同的 StatefulWidget 时。
有几种方法可以避免这个问题。最简单的方法是使用 Builder 来获取位于 Scaffold 下的上下文。有关这方面的示例,请参阅 Scaffold.of() 的文档: https://api.flutter.dev/flutter/material/Scaffold/of.html
更有效的解决方案是将构建功能拆分为多个小部件。这引入了一个新的上下文,您可以从中获取 Scaffold。在此解决方案中,您将拥有一个外部小部件,该小部件创建由新内部小部件的实例填充的 Scaffold,然后在这些内部小部件中,您将使用 Scaffold.of()。
一个不太优雅但更方便的解决方案是将 GlobalKey 分配给 Scaffold,然后使用 key.currentState 属性来获取 ScaffoldState 而不是使用 Scaffold.of() 函数。
【讨论】:
这是另一个以编程方式从汉堡包图标打开抽屉的示例,并且没有 Appbar:-
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
var scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
key: scaffoldKey,
drawer: new Drawer(
child: new ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
//Do some stuff here
//Closing programmatically - very less practical use
scaffoldKey.currentState.openEndDrawer();
},
)
],
),
),
body: Stack(
children: <Widget>[
new Center(
child: new Column(
children: <Widget>[],
)),
Positioned(
left: 10,
top: 20,
child: IconButton(
icon: Icon(Icons.menu),
onPressed: () => scaffoldKey.currentState.openDrawer(),
),
),
],
),
),
);
}
}
【讨论】:
调用 Scaffold.of 不起作用,因为上下文不包含 Scaffold。上面的一些解决方案忽略了这一点,其他解决方案使用了 GlobalKey。我相信最干净的解决方案是将按钮包装在 Builder 中:
Scaffold(
drawerEnableOpenDragGesture: false, // Prevent user sliding open
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text("Some Title"),
actions: [
Builder(builder: (context) => // Ensure Scaffold is in context
IconButton(
icon: Icon(Icons.settings),
onPressed: () => Scaffold.of(context).openDrawer()
)),
],
),
// TODO ...
)
【讨论】:
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
"Infilon Technologies",
style:
TextStyle(fontFamily: "Poppins", fontWeight: FontWeight.w600),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.menu),
onPressed: () {
if (_scaffoldKey.currentState.isEndDrawerOpen) {
_scaffoldKey.currentState.openDrawer();
} else {
_scaffoldKey.currentState.openEndDrawer();
}
},
),
],
),
【讨论】:
您必须将小部件包装在新的 BuildContext 中,因为您使用的上下文很可能是外部上下文,并且不知道 Scaffold。
drawer: Builder(
builder: (BuildContext internalContext) {
return _drawer(internalContext);
},
),
查看完整代码
class SampleAppPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: _appBar(context),
drawer: new Builder(
builder: (BuildContext internalContext) {
return _drawer(internalContext);
},
),
body: new Builder(
builder: (BuildContext internalContext) {
return _body(internalContext);
},
),
),
);
}
Widget _appBar(BuildContext context) {
return new AppBar(
title: new Text('Drawer example'),
);
}
Widget _drawer(BuildContext context) {
return new Center(
child: new RaisedButton(
child: new Text('Close drawer'),
onPressed: () => Navigator.of(context).pop(),
),
);
}
Widget _body(BuildContext context) {
return new Column(
children: <Widget>[
new RaisedButton(
child: new Text('Open via Scaffold context'),
onPressed: () => Scaffold.of(context).openDrawer(),
),
],
);
}
}
【讨论】: