Флаттер: унаследованные виджеты и маршруты
Я хочу иметь унаследованный виджет в корне моего приложения, который будет содержать моих поставщиков данных, которые я буду использовать в приложении. Итак, у меня есть этот унаследованный виджет, но каждый раз, когда я пытаюсь загрузить его, я получаю это 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 на более высоком уровне; перед навигатором. поэтому я вставил это в 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)
1 ответ
У меня долгое время была такая же проблема, и я понял, что если вы обернете MaterialApp унаследованным виджетом, ваши данные будут доступны через все приложение. Но в вашем случае вам необходимо передать данные после входа пользователя в систему, поэтому для этого вам нужно создать новый навигатор и обернуть его своим унаследованным виджетом. Вы можете увидеть этот проект 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,
),
);
}
}
Это потому, что вы пытаетесь получить доступ CoolApp
который находится в пути /
с другого маршрута (динамический).
Но внутри вашего динамического маршрута нет CoolApp
, Так CoolApp.of(context)
возвращает ноль, и, следовательно, доступ .data
сбои.
Вам нужно найти способ иметь CoolApp
экземпляр внутри вашего нового маршрута.
Для получения дополнительной информации взгляните на Получить доступ к контексту InheritedWidget