【问题标题】:How to detect the drawer is closed on flutter?如何检测抽屉是否关闭?
【发布时间】:2019-02-21 13:50:59
【问题描述】:

作为标题。既然我们可以检测到抽屉已打开,但这是否可以检查它是否已关闭?谢谢。

【问题讨论】:

  • 请详细说明您的问题并尝试解释更多。向我们提供您迄今为止所尝试的方法。

标签: dart flutter


【解决方案1】:

旧的 Flutter SDK 中缺少此功能,因此我开发了此功能,并已在 Flutter 2.0.0 中发布。

只需在 Scaffold 中使用回调

return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      drawer: NavDrawer(),
      onDrawerChanged: (isOpen) {
        // write your callback implementation here
        print('drawer callback isOpen=$isOpen');
      },
      endDrawer: NavDrawerEnd(),
      onEndDrawerChanged: (isOpen) {
        // write your callback implementation here
        print('end drawer callback isOpen=$isOpen');
      },
      body:
      ...

2.0.0合并拉取请求:https://github.com/flutter/flutter/pull/67249

编码愉快!

【讨论】:

    【解决方案2】:

    声明一个 GlobalKey 来引用您的抽屉:

    GlobalKey _drawerKey = GlobalKey();
    

    把钥匙放在抽屉里:

     drawer: Drawer(
                      key: _drawerKey,
    

    检查您的抽屉是否可见:

     final RenderBox box = _drawerKey.currentContext?.findRenderObject();
     if (box != null){
        //is visible
     } else {
       //not visible  
    } 
    

    【讨论】:

    • 如果我想用onPressed 改变抽屉按钮的外观,这将不起作用,因为那时抽屉仍然为空。
    【解决方案3】:

    您可以在下面复制粘贴运行完整代码
    您可以用StatefulWidget 包装Drawer 并将callback 放入initState()dispose()
    initState() 将调用widget.callback(true); 表示打开
    dispose() 将调用widget.callback(false); 表示关闭
    在这种情况下也可以使用幻灯片

    代码sn-p

    drawer: CustomDrawer(
            callback: (isOpen) {
              print("isOpen ${isOpen}");
              WidgetsBinding.instance.addPostFrameCallback((_) {
                setState(() {
                  _isDrawerOpen = isOpen;
                });
              });
            },
    ...
    class CustomDrawer extends StatefulWidget {
      CustomDrawer({
        Key key,
        this.elevation = 16.0,
        this.child,
        this.semanticLabel,
        this.callback,
      })  : assert(elevation != null && elevation >= 0.0),
            super(key: key);
    
      final double elevation;
      final Widget child;
      final String semanticLabel;
    
      final DrawerCallback callback;
      @override
      _CustomDrawerState createState() => _CustomDrawerState();
    }
    
    class _CustomDrawerState extends State<CustomDrawer> {
      @override
      void initState() {
        if (widget.callback != null) {
          widget.callback(true);
        }
    
        super.initState();
      }
    
      @override
      void dispose() {
        if (widget.callback != null) {
          widget.callback(false);
        }
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Drawer(
            key: widget.key,
            elevation: widget.elevation,
            semanticLabel: widget.semanticLabel,
            child: widget.child);
      }
    }
    

    工作演示

    完整代码

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      bool _isDrawerOpen = false;
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          drawer: CustomDrawer(
            callback: (isOpen) {
              print("isOpen ${isOpen}");
              WidgetsBinding.instance.addPostFrameCallback((_) {
                setState(() {
                  _isDrawerOpen = isOpen;
                });
              });
            },
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                DrawerHeader(
                  child: Text('Drawer Header'),
                  decoration: BoxDecoration(
                    color: Colors.blue,
                  ),
                ),
                ListTile(
                  title: Text('Item 1'),
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(builder: (context) => SecondRoute()),
                    );
                  },
                ),
                ListTile(
                  title: Text('Item 2'),
                  onTap: () {
                    // Update the state of the app.
                    // ...
                  },
                ),
              ],
            ),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Align(
                  alignment: Alignment.centerRight,
                  child: Text(
                    _isDrawerOpen.toString(),
                  ),
                ),
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    
    class CustomDrawer extends StatefulWidget {
      CustomDrawer({
        Key key,
        this.elevation = 16.0,
        this.child,
        this.semanticLabel,
        this.callback,
      })  : assert(elevation != null && elevation >= 0.0),
            super(key: key);
    
      final double elevation;
      final Widget child;
      final String semanticLabel;
    
      final DrawerCallback callback;
      @override
      _CustomDrawerState createState() => _CustomDrawerState();
    }
    
    class _CustomDrawerState extends State<CustomDrawer> {
      @override
      void initState() {
        if (widget.callback != null) {
          widget.callback(true);
        }
    
        super.initState();
      }
    
      @override
      void dispose() {
        if (widget.callback != null) {
          widget.callback(false);
        }
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Drawer(
            key: widget.key,
            elevation: widget.elevation,
            semanticLabel: widget.semanticLabel,
            child: widget.child);
      }
    }
    
    class SecondRoute extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text("route test"),
            ),
            body: Text("SecondRoute"));
      }
    }
    

    【讨论】:

      【解决方案4】:

      您可以简单地使用 onDrawerChanged 来检测抽屉是在 Scaffold 小部件中打开还是关闭。

      属性:

      {void 函数(bool)? onDrawerChanged} 类型:无效函数(布尔)? Scaffold.drawer 打开或关闭时调用的可选回调。

      示例:

      @override Widget build(BuildContext context) {
      
      return Scaffold(
        onDrawerChanged:(val){
          if(val){
            setState(() {
              //foo bar;
            });
          }else{
            setState(() {
              //foo bar;
            });
          }
      },     
        drawer: Drawer(        
            child: Container(
            )
        ));
      }
      

      【讨论】:

        【解决方案5】:

        当您单击一个抽屉项目时,您将导航到一个新屏幕,在Navigator.push(..) 调用中,您可以添加一个.then(..) 子句,然后知道抽屉项目屏幕何时弹出。

        这里是抽屉项的ListTile,它在单击时调用Navigator.push(..),以及相关的.then(..)回调块:

             ListTile(
                  title: Text('About App'),
                  onTap: () {
                    Navigator.push(
                      _ctxt,
                      MaterialPageRoute(builder: (context) => AboutScreen()),
                    ).then(
                      (value) {
                        print('Drawer callback for About selection');
                        if (_onReadyCallback != null) {
                          _onReadyCallback();
                        }
                      },
                    );
                  }),
        

        _onReadyCallback() 表示您可以传入的函数参数。

        我发现这是一种方法——利用来自.push() 调用的.then() 回调——对于理解 Flutter 来说是一个非常有用的概念。

        非常感谢这里的主要 2 个答案: Force Flutter navigator to reload state when popping

        这是完整的Drawer 代码:

        Drawer drawer = Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              DrawerHeader(
                decoration: BoxDecoration(
                  color: Color(0xFF7FAD5F),
                ),
                child: Text(App.NAME_MENU),
              ),
              ListTile(
                  title: Text('About App'),
                  onTap: () {
                    Navigator.push(
                      _ctxt,
                      MaterialPageRoute(builder: (context) => AboutScreen()),
                    ).then(
                      (value) {
                        print('Drawer callback for About selection');
                        if (_onReadyCallback != null) {
                          _onReadyCallback();
                        }
                      },
                    );
                  }),
            ],
          ),
        );
        

        【讨论】:

          【解决方案6】:

          我建议你使用这个包:https://pub.dev/packages/visibility_detector.

          之后,您应该为 Drawer 小部件分配一个 GlobalKey,例如 _drawerKey,之后您就可以像这样检测抽屉何时关闭:

          VisibilityDetector(
                        key: _drawerKey,
                        child: Container(),
                        onVisibilityChanged: (info) {
                          if (info.visibleFraction == 0.0) {
                            // drawer not visible.
                          }
                        },
                      )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-08
            • 1970-01-01
            • 2015-06-27
            • 1970-01-01
            • 2020-12-26
            • 2012-01-02
            相关资源
            最近更新 更多