我希望能通过编程方式打开Drawer
,而不是通过滑动来打开它。如何禁用该滑动功能(即Drawer
的触摸功能)?
我希望能通过编程方式打开Drawer
,而不是通过滑动来打开它。如何禁用该滑动功能(即Drawer
的触摸功能)?
使用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 ...
)
Scaffold
的属性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。
一个干净的方法是将按钮包装在生成器中。我编辑了答案以包括一个最小的完整工作示例。
Scaffold是一个实现材料设计原则的小部件,因此请注意,为了能够调用此方法,您需要import 'package:flutter/material.dart';
且您的小部件需要有一个MaterialApp作为祖先。
与许多Flutter事物一样,确保Scaffold处于上下文中还有其他解决方案。
在我看来,错误消息是Flutter框架中最好的功能之一,请允许我谦卑地建议始终仔细阅读它们并探索它们指向的文档。
例如,如果在适当的上下文之外调用openDrawer,则会收到以下错误消息的一部分:
使用不包含Scaffold的上下文调用Scaffold.of()。
从传递给Scaffold.of()的上下文开始,找不到Scaffold祖先。通常会发生这种情况,当提供的上下文来自与实际创建正在寻找的Scaffold小部件的build函数相同的StatefulWidget时。
有几种方法可以避免此问题。最简单的方法是使用Builder获取“位于”Scaffold下的上下文。关于此的示例,请参见Scaffold.of()的文档: https://api.flutter.dev/flutter/material/Scaffold/of.html
更有效的解决方案是将生成函数分成几个小部件。这会引入一个新的上下文,您可以从中获取Scaffold。在此解决方案中,您将具有创建由新的内部小部件实例填充的Scaffold的外部小部件,然后在这些内部小部件中使用Scaffold.of()。
一个不太优雅但更快捷的解决方案是将GlobalKey分配给Scaffold,然后使用key.currentState属性而不是使用Scaffold.of()函数来获取ScaffoldState。
因为上下文中不包含Scaffold,所以调用Scaffold.of无效。一些上面的解决方案忽略了这一点,另一些使用了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 ...
)
以下是另一个通过汉堡图标程序化地打开抽屉、不使用应用栏的示例:
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(),
),
),
],
),
),
);
}
}
只需按照以下步骤:
在类中创建一个变量,如下所示
var scaffoldKey = GlobalKey<ScaffoldState>();
然后在你的脚手架中像这样使用这个键
Scaffold(
key: scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: () {
scaffoldKey.currentState?.openDrawer();
},
icon: Icon(
Icons.menu,
color: ExtraColors.PRIMARY_800,
)),
title: Text(
'${AppStrings.appName}',
),
centerTitle: true,
),
)
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();
}
},
),
],
),
您可以使用这个完美的方法打开抽屉 它适用于Flutter 2.12以上的空值安全模块
class DashBoardScreen extends StatefulWidget {
final String? screen;
const DashBoardScreen(this.screen, {super.key});
@override
State<DashBoardScreen> createState() => _DashBoardScreenState();
}
class _DashBoardScreenState extends State<DashBoardScreen> {
DashBoardScreenController controller =
Get.put(getIt<DashBoardScreenController>());
@override
Widget build(BuildContext context) {
controller.scaffoldKey = GlobalKey<ScaffoldState>();
return Obx(() => Scaffold(
key: controller.scaffoldKey,
onDrawerChanged: (isOpened) {
if (!isOpened) {
setState(() {});
}
},
appBar: AppBar(
title: const Text("Test drawer App"),
actions: const [
const Padding(
padding: EdgeInsets.only(right: 20),
child: Icon(Icons.search))
],
leading: UnconstrainedBox(
child: GestureDetector(
onTap: () {
controller.scaffoldKey.currentState!.openDrawer();
},
child: const AbsorbPointer(
absorbing: true,
child: SizedBox(
height: 50,
child: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(
"https://cdn.pixabay.com/photo/2014/07/09/10/04/man-388104_960_720.jpg",
)),
),
),
),
),
),
drawerEdgeDragWidth:
kIsWeb ? MediaQuery.of(context).size.width * 0.2 : null,
drawer: Drawer(
key: controller.scaffoldKey,
child: ListView(
children: [
DropdownMenuItem(onTap: () {}, child: const Text("Add Anime"))
],
)),
body: widget.screen == StringVariables.ADD_ANIME
? AddAnimeFragment(widget.screen!)
: Container(),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Add Anime',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Favourite',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
currentIndex: controller.bottomSheetIndex.value,
selectedItemColor: ColorName.primaryColor,
onTap: (s) {
controller.bottomSheetIndex.value = s;
},
),
));
}
}
Scaffold.of(context).openEndDrawer();
drawer
(从左至右),则应使用以下代码:Scaffold.of(context).openDrawer();