我是Flutter的新手,对InheritedWidget
如何使用路线感到困惑。我正在将SQLite数据库与sqflite库一起使用。基本上,我想要实现的是,在启动应用程序时,我希望所有不需要数据库的小部件立即显示。例如,我的Scaffold
的bottomNavigationBar不需要数据库,但是主体需要数据库。因此,我想立即显示bottomNavigationBar,并在正文中显示CircularProgressIndicator
。打开数据库后,我希望正文显示从数据库加载的内容。
因此,为了实现这一目标,我在FutureBuilder
之前使用Scaffold
打开数据库。当Future
未完成时,我将null
传递给抽屉,将CircularProgressBar
传递给主体,并将bottomNavigationBar照常传递。 Future
完成后,我用自己的HomePage
(称为InheritedWidget
)包装了抽屉和主体(称为DataAccessor
)。这似乎可行,因为我可以在DataAccessor
小部件中访问HomePage
。但是,当我在抽屉中使用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
?我还尝试用我的Scaffold
包装整个DataAccessor
(并且在加载数据库时将其设置为null),但是问题仍然存在,我无法获取我的DataAccessor
在我的SettingsScreen
中。
我已经读到一个可能的解决方案是将我的InheritedWidget
放在MaterialApp
之前,但是我不想诉诸于此。我不希望在打开数据库时显示一个新的屏幕,我希望不需要显示数据库的窗口小部件。这应该是可能的。
谢谢!
答案 0 :(得分:1)
最后一段中的解决方案是您需要的。 MaterialApp
包含管理路由的Navigator
,因此,您的所有路由都可以访问必须位于InheritedWidget
上方(即高于)的同一Navigator
。 MaterialApp
。
使用Remi's method,您将得到一个像这样的小部件树:
MyApp
(静态.of()
返回MyAppState
)MyAppState
,其build
返回_MyInherited(child: MaterialApp(...))
,并且其initState
开始加载数据库,并在加载时调用setState
。建立首页时,您可以通过MyAppState
访问.of
,因此可以确定数据库是否已加载。如果还没有,则只需构建数据库独立的小部件;如果有,则构建所有小部件。