Flutter:如何以编程方式打开 Drawer

kri*_*aji 44 dart flutter flutter-layout

我想以Drawer编程方式打开而不是通过滑动它,如何禁用该滑动功能(抽屉的触摸功能)

Cop*_*oad 84

空安全码

  • 使用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
        ),
      );
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用Builder

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        drawer: Drawer(),
        floatingActionButton: Builder(builder: (context) {
          return FloatingActionButton(
            onPressed: () => Scaffold.of(context).openDrawer(), // <-- Opens drawer.
          );
        }),
      );
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • 是的,我改变了问题,因为我问错了,对此感到抱歉,您能否提供构建自定义抽屉的来源 (2认同)

giu*_*ulp 48

  1. 要禁用滑动打开功能,您可以将drawerEnableOpenDragGestureScaffold 上的属性设置为 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()
            ),
          ),
        )
      )
    );
  }
}

Run Code Online (Sandbox Code Playgroud)
  1. 要使用编程方式打开抽屉,Scaffold.of(context)您必须确保(感谢Krolaw!)进行调用的上下文知道 Scaffold。

    一种干净的方法是将按钮包装在构建器中。我已经编辑了答案以包含一个最小的完整工作示例。

    Scaffold 是一个实现材料设计原则的小部件,因此请注意,为了能够调用此方法,您需要调用该方法,import 'package:flutter/material.dart';并且您的小部件需要有一个 MaterialApp 作为祖先。

代码笔演示


与许多 Flutter 事物一样,还有其他解决方案可以确保 Scaffold 处于上下文中。

错误消息是 IMO 中 Flutter 框架的最佳功能之一,请允许我谦虚地建议始终彻底阅读它们并探索它们指向的文档。

例如,这是在正确上下文之外调用 openDrawer 时得到的错误消息的一部分:

Scaffold.of() 使用不包含 Scaffold 的上下文调用。

从传递给 Scaffold.of() 的上下文开始,找不到任何 Scaffold 祖先。这通常发生在提供的上下文来自与其构建函数实际创建正在寻找的 Scaffold 小部件的相同 StatefulWidget 时。

有几种方法可以避免这个问题。最简单的方法是使用 Builder 来获取 Scaffold “下”的上下文。有关此示例,请参阅 Scaffold.of() 的文档:https : //api.flutter.dev/flutter/material/Scaffold/of.html

更有效的解决方案是将您的构建功能拆分为多个小部件。这引入了一个新的上下文,您可以从中获取 Scaffold。在此解决方案中,您将拥有一个外部小部件,用于创建由新内部小部件的实例填充的 Scaffold,然后在这些内部小部件中您将使用 Scaffold.of()。

一个不太优雅但更方便的解决方案是为 Scaffold 分配一个 GlobalKey,然后使用 key.currentState 属性来获取 ScaffoldState 而不是使用 Scaffold.of() 函数。

  • 这个方法行不通! (4认同)

Gag*_*hir 11

这是从汉堡包图标以编程方式打开抽屉的另一个示例,而没有 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(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 9

调用 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 ...
)
Run Code Online (Sandbox Code Playgroud)


Ras*_*han 5

只需执行以下步骤

像这样在类中创建一个变量

var scaffoldKey = GlobalKey<ScaffoldState>();
Run Code Online (Sandbox Code Playgroud)

然后像这样在你的脚手架中使用这个键

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,
      ),
   )
Run Code Online (Sandbox Code Playgroud)