gpt4 book ai didi

dart - 在新 route 无法访问 InheritedWidget

转载 作者:IT王子 更新时间:2023-10-29 06:57:45 25 4
gpt4 key购买 nike

我是 Flutter 的新手,对 InheritedWidget 如何与路由一起工作感到困惑。我正在使用带有 sqflite 库的 SQLite 数据库。基本上,我想要实现的是,当我的应用程序启动时,我希望所有不需要数据库的小部件立即显示。例如,我的 Scaffold 的 bottomNavigationBar 不需要数据库,但主体需要。所以我希望 bottomNavigationBar 立即显示,并在正文中显示 CircularProgressIndicator。打开数据库后,我希望正文显示从数据库加载的内容。

因此,在尝试实现此目的时,我在 Scaffold 之前使用了 FutureBuilder 打开数据库。当 Future 未完成时,我为抽屉传递了 null,为主体传递了一个 CircularProgressBar,并照常传递了 bottomNavigationBar。当 Future 完成时,我用它们自己的 InheritedWidget(称为 DataAccessor)包装抽屉和主体(称为 HomePage) >).这似乎可行,因为我可以在我的 HomePage 小部件中访问 DataAccessor。但是,当我使用抽屉中的 Navigator 导航到我的 SettingsScreen 时,我的 DataAccessor 不可访问并返回 null。

下面是一些示例代码,没有使用数据库,只是延迟了 5 秒的 Future:

import 'package:flutter/material.dart';

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

class App extends StatelessWidget {

@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: Future.delayed(Duration(seconds: 5)),
builder: (context, snapshot) {
Widget drawer;
Widget body;
if (snapshot.connectionState == ConnectionState.done) {
drawer = DataAccessor(
child: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Settings"),
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SettingsScreen()))
)
]
)
)
);
body = DataAccessor(child: HomePage());
}
else {
drawer = null;
body = Center(child: CircularProgressIndicator());
}
return Scaffold(
drawer: drawer,
body: body,
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Container(), title: Text("One")),
BottomNavigationBarItem(icon: Container(), title: Text("Two"))
]
)
);
}
)
);
}
}

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
DataAccessor dataAccessor = DataAccessor.of(context); //dataAccessor IS NOT null here
print("HomePage: ${dataAccessor == null}");
return Text("HomePage");
}
}

class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
DataAccessor dataAccessor = DataAccessor.of(context); //dataAccessor IS null here
print("SettingsScreen: ${dataAccessor == null}");
return Text("SettingsScreen");
}
}

class DataAccessor extends InheritedWidget {

DataAccessor({Key key, Widget child}) : super(key: key, child: child);

@override
bool updateShouldNotify(InheritedWidget oldWidget) => false;

static DataAccessor of(BuildContext context) => context.inheritFromWidgetOfExactType(DataAccessor);

}

有可能是我做错了。不确定将小部件存储在变量中的做法有多好。或者使用相同的 InheritedWidget 两次?我还尝试用我的 DataAccessor 包装整个 Scaffold (并在加载时将数据库设置为 null),但问题仍然存在,我无法得到我的 DataAccessor 在我的 SettingsScreen 中。

我读到一个可能的解决方案是将我的 InheritedWidget 放在 MaterialApp 之前,但我不想诉诸于此。我不希望在打开数据库时显示一个全新的屏幕,我希望显示不需要数据库的小部件。这在某种程度上应该是可能的。

谢谢!

最佳答案

最后一段中的解决方案正是您所需要的。 MaterialApp 包含管理路由的 Navigator,因此您的所有路由都可以访问必须位于Navigator,即在 MaterialApp 之上。

使用Remi's method你最终会得到一个像这样的小部件树:

  • MyApp(具有返回 MyAppState 的静态 .of())
  • MyAppState,它的 build 返回 _MyInherited(child: MaterialApp(...)) 并且它的 initState开始加载数据库,加载时调用 setState

在构建主页时,您可以通过 .of 访问 MyAppState,因此可以确定数据库是否已加载。如果没有,只需构建独立于数据库的小部件;如果有,构建所有小部件。

关于dart - 在新 route 无法访问 InheritedWidget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55269649/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com