当前,我从BuildContext
中的build
方法中获得了HomeScreen
,然后必须将其传递给_gridSliver
,然后传递给_storeCard
。
如何编写代码,这样我就不需要将上下文传递下去了?
也许我可以创建一个名为StatelessWidget
的新私有_StoreCard
,它将拥有自己的build
方法和因此自己的BuildContext
?
class HomeScreen extends StatelessWidget {
HomeScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, List<MyStore.Store>>(
converter: (Store<AppState> store) => store.state.home.stores,
builder: (BuildContext context, List<MyStore.Store> stores) =>
CustomScrollView(slivers: <Widget>[_gridSliver(stores, context)]));
}
Widget _gridSliver(stores, context) {
return SliverGrid(
delegate: SliverChildListDelegate(List<Widget>.from(stores.map(_storeCard, context))));
}
Widget _storeCard(MyStore.Store store, BuildContext context) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => StoreScreen(storeId: store.id)),
);
},
child: Container(child: Text(store.name))
);
}
}
此问题的另一个实例是我在子功能上导航。
@override
Widget build(BuildContext context) {
return Column(
children: [
WhiteButton(text: "Login with Facebook", onPressed: _loginWithFacebook),
WhiteButton(text: "Login with Google", onPressed: _loginWithGoogle),
])
)
}
_loginWithFacebook(context) async {
...
var user = User.fromFacebook(result.accessToken.token, json.decode(graphResponse.body));
await _login(user, context);
}
}
_loginWithGoogle(context) async {
...
GoogleSignInAccount googleUser = await _googleSignIn.signIn();
await _login(User.fromGoogle(googleUser), context);
}
_login(user, context) async {
var fetchedUser = await MeService.getUser(user);
if (fetchedUser != null) {
loginSuccess(fetchedUser);
Navigator.popUntil(context, ModalRoute.withName(MainRoutes.root));
} else {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => RegisterScreen(user: user)),
);
}
}
答案 0 :(得分:3)
要获得新的BuildContext
,您有两种主要解决方案:
将子树的一部分提取到新的小部件中,通常为StatelessWidget
。然后使用BuildContext
方法中的build
使用Builder
小部件,该小部件基本上是可重用的小部件,用于获取BuildContext
:
示例:
@override
Widget build(BuildContext context) {
return Builder(
builder: (context) {
// do something with this new context
},
);
}
答案 1 :(得分:1)
您必须使用使用Inherited Widget的Bloc模式,但仍然必须以更直接的方式传递上下文。我建议使用Stephen Grider的this app来了解整个过程。他在教程中解释了如何将整个内容放在一起,但我无法将您链接到该内容,因为那将是广告。
想法是,首先创建一个包含逻辑的文件Bloc.dart,然后在Provider.dart中创建一个称为Provider的文件。
Provider.dart:
class Provider extends InheritedWidget {
final bloc = Bloc();
Provider({Key key, Widget child}) : super(key: key, child: child);
bool updateShouldNotify(_) => true;
static Bloc of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(Provider) as Provider).bloc;
}
}
在包含Material App的文件中,使用提供者包装Material App:
Widget build(BuildContext context) {
return Provider(
child: MaterialApp(
然后在其他三个小类中的每个其他类中使用提供程序。
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bloc = Provider.of(context); // this is where you insert the provider
return StoreConnector<AppState, List<MyStore.Store>>(
converter: (Store<AppState> store) => store.state.home.stores,
builder: (BuildContext context, List<MyStore.Store> stores) =>
CustomScrollView(slivers: <Widget>[_gridSliver(stores, context)]));
}
Widget _gridSliver(stores) {
final bloc = Provider.of(context);
return SliverGrid(
delegate: SliverChildListDelegate(List<Widget>.from(stores.map(_storeCard, context))));
}
Widget _storeCard(MyStore.Store store) {
final bloc = Provider.of(context);
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => StoreScreen(storeId: store.id)),
);
},
child: Container(child: Text(store.name))
);
}
}
我是个全神贯注的菜鸟,吃了所有的盐,但这就是我要用的。希望对您有所帮助。