Flutter:继承的小部件和路由

时间:2018-04-22 17:33:48

标签: dart flutter inherited-widget

我希望在我的应用程序的根目录下有一个继承的小部件,它将包含我的数据提供程序,我会在整个应用程序中使用它。所以我有这个继承的小部件,但每次我尝试加载它时,我得到这个The getter 'data' was called on null,我无法弄清楚原因。

所以这是我的main.dart:

void main() => runApp(new MatAppRoot());

class MatAppRoot extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'MyCoolApp',
      routes: <String, WidgetBuilder>{
        'Login': (BuildContext context) => new LoginPage(),
        'Cool': (BuildContext context) => new CoolPage(),
      },
      home: new CoolApp(),
    );
  }
}

class CoolAppextends StatefulWidget {

  final Widget child;

  CoolApp({this.child});

  @override
  CoolAppState createState() => new CoolAppState();

  static CoolAppState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(CoolInherit) as CoolInherit).data;
  }
}

class CoolAppState extends State<CoolApp> {
  String randomString = 'AYEEAS!!!';

  @override
  void initState() { super.initState();
    Navigator.of(context).pushNamedAndRemoveUntil('Login', (Route<dynamic> route) => false);
  }

  @override
  Widget build(BuildContext context) {
    return new CoolInherit(
      data: this,
      child: new LoginPage(),
    );
  }

}

class CoolInherit extends InheritedWidget {

  final CoolAppState data;

  CoolInherit({
    Key key,
    this.data,
    Widget child,
  }): super(
    key: key,
    child: child
  );

  @override
  bool updateShouldNotify(CoolInherit old) {
    return true;
  }
}

然后我的LoginPage基本上会在登录后重定向,如下所示:

if (logInSuccessful) {
  Navigator.of(context).pushNamedAndRemoveUntil('Cool', (Route<dynamic> route) => false);
}

在我的Cool页面中,当我点击这样的按钮时,我会尝试加载另一个页面:

viewCoolDetails() {
  Navigator.push(
    context,
    new MaterialPageRoute(builder: (context) => new CoolDetailsPage()),
  );
}

但在我的CoolDetailsPage中,当我执行此操作时崩溃:

@override
Widget build(BuildContext context) {
  final inheritedWidget = CoolApp.of(context);
  print(inheritedWidget.randomString);   <-- ERROR: The getter 'data' was called on null
  return new Text('Cool!');
}

错误详情:

I/flutter ( 6129): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 6129): The following NoSuchMethodError was thrown building CoolDetailsPage(dirty, state:
I/flutter ( 6129): _CoolDetailsPage#ba0bb):
I/flutter ( 6129): The getter 'data' was called on null.
I/flutter ( 6129): Receiver: null
I/flutter ( 6129): Tried calling: data
I/flutter ( 6129):
I/flutter ( 6129): When the exception was thrown, this was the stack:
I/flutter ( 6129): #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:46:5)
I/flutter ( 6129): #1      CoolApp.of (/lib/main.dart:56:83)
... etc etc

main.dart:56是return (context.inheritFromWidgetOfExactType(CoolInherit) as CoolInherit).data;所以如果我的侦探工作达到标准,我怀疑它是导航/上下文的一部分,这阻止了我的最终小部件访问inheritedWidget,但我&# 39;我不确定。

更新:

我能说的最好,我需要在更高级别插入我的InheritedWidget;导航员之前。所以我把它插入到MaterialApp:

builder: (context, child) {
  return new CoolApp(child: child);
},

但是没有看到工作......

E/flutter (32321): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (32321): Navigator operation requested with a context that does not include a Navigator.
E/flutter (32321): The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
E/flutter (32321): #0      Navigator.of.<anonymous closure> (package:flutter/src/widgets/navigator.dart:1180:9)
E/flutter (32321): #1      Navigator.of (package:flutter/src/widgets/navigator.dart:1187:6)

2 个答案:

答案 0 :(得分:1)

很长一段时间以来,我都遇到过同样的问题,我意识到,如果您将MaterialApp与Inherited Widget封装在一起,您的数据就可以通过整个应用程序访问。但是,在您的情况下,您需要在用户登录后传递数据,您需要创建一个新的导航器并将其与继承的小部件一起包装。。您可以看到此项目https://github.com/johnstef99/inherited-widget-demo

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'InheritedWidget Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyNav(),
    );
  }
}

Route generatePage(child) {
  return MaterialPageRoute(builder: (context) => child);
}

class MyNav extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MyData(
      data: 'omg',
      child: Navigator(
        onGenerateRoute: (settings) {
          switch (settings.name) {
            case 'page1':
              return generatePage(PageOne());
            case 'page2':
              return generatePage(PageTwo());
            case 'page3':
              return generatePage(PageThree());
          }
        },
        initialRoute: 'page1',
      ),
    );
  }
}

class MyData extends InheritedWidget {
  MyData({Key key, this.child, this.data}) : super(key: key, child: child);

  final Widget child;
  final String data;

  static MyData of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(MyData) as MyData);
  }

  @override
  bool updateShouldNotify(MyData oldWidget) {
    return true;
  }
}

class PageOne extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Page 1'),
      ),
      backgroundColor: Colors.red,
      body: RaisedButton(
        child: Text("Goto page 2, data=${MyData.of(context).data}"),
        onPressed: () {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (_) => PageTwo()));
        },
      ),
    );
  }
}

class PageTwo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Page 2'),
      ),
      backgroundColor: Colors.red,
      body: RaisedButton(
        child: Text("Goto page 3, data=${MyData.of(context).data}"),
        onPressed: () {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (_) => PageThree()));
        },
      ),
    );
  }
}

class PageThree extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Page 3'),
      ),
      backgroundColor: Colors.green,
      body: RaisedButton(
        child: Text("Goto page 4, data=${MyData.of(context).data}"),
        onPressed: null,
      ),
    );
  }
}

答案 1 :(得分:0)

这是因为您尝试从另一条路线(动态)访问路线CoolApp中的/

但在你的动态路线中,没有CoolApp。因此CoolApp.of(context)返回null,因此访问.data崩溃。

您需要找到一种在新路线中拥有CoolApp实例的方法。

有关更多信息,请查看Get access to the context of InheritedWidget