Flutter从不同的Dart文件访问父脚手架

时间:2018-07-09 20:35:34

标签: dart flutter

我有这个:

  final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        key: _scaffoldkey,
        drawer: Menu(),
        appBar: AppBar(
          title: Container(
            child: Text('Dashboard'),
          ),
          bottom: TabBar(
            tabs: <Widget>[
              ...
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            ...
          ],
        ),
      ),
    );
  }
}

现在,drawer: Menu()从另一个menu.dart文件导入,如下所示:

class Menu extends StatelessWidget {

  final GlobalKey<ScaffoldState> drawerKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return new Drawer(
      key: drawerKey,
      child: new ListView(
        children: <Widget>[
          new ListTile(
            dense: true,
            title: new Text('My Text'),
            onTap: () {
              // On tap this, I want to show a snackbar.
              scaffoldKey.currentState.showSnackBar(showSnack('Error. Could not log out'));
            },
          ),
        ],
      ),
    );
  }
}

通过上述方法,我得到了

NoSuchMethodError: The method 'showSnackBar' was called on null.

一个简单的解决方案是将全部menu.dart的内容直接塞入drawer: ...中。

我正在查看的另一种方法是能够引用父支架以显示小吃栏。

如何做到这一点?

为什么甚至不能只在Flutter的任何地方打电话给快餐店,而必须通过脚手架来完成它?为什么?

3 个答案:

答案 0 :(得分:7)

您应尽量避免使用GlobalKey;使用Scaffold.of获取ScaffoldState几乎总是更好。由于您的菜单位于小部件树中的支架下方,因此Scaffold.of(context)会做您想要的事情。

您尝试执行的操作不起作用的原因是,您要创建两个单独的GlobalKey-每个都有自己的对象。将它们视为全局指针-由于您要创建两个不同的指针,因此它们指向不同的事物。而且状态实际上应该是分析失败,因为您将错误的类型传递到了抽屉的key字段中。

如果由于某些原因绝对必须使用GlobalKeys,最好将外部小部件中创建的实例作为成员(即Menu)传递到this.scaffoldKey类中,但这不是推荐。

使用Scaffold.of,这是您的代码在onTap函数中的样子:

onTap: () {
  // On tap this, I want to show a snackbar.
  Scaffold.of(context).showSnackBar(showSnack('Error. Could not log out'));
},

答案 1 :(得分:0)

您可以通过使用构建器小部件来实现此功能,而无需将单独的GlobalKey或传递密钥作为参数。只需将小部件包装到Builder小部件

class CustomDrawer extends StatelessWidget {@override Widget build(BuildContext context) {
return new Drawer(
  child: new ListView(
    children: <Widget>[
      new Builder(builder: (BuildContext innerContext) {
        return ListTile(
            dense: true,
            title: new Text('My Text'),
            onTap: () {
              Navigator.of(context).pop();
              Scaffold.of(innerContext).showSnackBar(SnackBar(
                content: Text('Added added into cart'),
                duration: Duration(seconds: 2),
                action: SnackBarAction(label: 'UNDO', onPressed: () {}),
              ));
            }
            );
      })
    ],
  ),
);}}

答案 2 :(得分:0)

从你的第一个问题
要在菜单小部件中引用父脚手架,您可以将 _scaffoldkey 作为参数传递给菜单小部件,并使用 ScaffoldMessenger.of() 显示小吃栏,如下所示

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // Root Widget
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // App name
      title: 'Flutter SnackBar',
      // Theme
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Test(title: 'SnackBar'),
    );
  }
}
 

class Test extends StatefulWidget {
  final String? title;

  final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
  Test({@required this.title});

  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        key: widget._scaffoldkey,
        drawer: Menu(parentScaffoldkey:widget._scaffoldkey),
        appBar: AppBar(
          title: Container(
            child: Text('Dashboard'),
          ),
          bottom: TabBar(
            tabs: <Widget>[
              Tab(text:"Home"),
              Tab(text:"About")
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            Text("Home"),
            Text("About")
          ],
        ),
      ),
    );
  }
}

如图所示的菜单部分

class Menu extends StatelessWidget {
  final parentScaffoldkey;
  
  Menu({this.parentScaffoldkey});

  @override
  Widget build(BuildContext context) {
    return new Drawer(
      child: new ListView(
        children: <Widget>[
          new ListTile(
            dense: true,
            title: new Text('My Text'),
            onTap: () {
              // On tap  show a snackbar.
             // ScaffoldMessenger will call the nearest Scaffold to show snackbar
            ScaffoldMessenger.of(this.parentScaffoldkey.currentContext).showSnackBar(SnackBar(content:Text('Error. Could not log out')));
            },
          ),
        ],
      ),
    );
  }
}

此外,您必须通过 Scaffold 调用小吃店,因为它提供了 SnackBar API 并对其进行管理