Wal*_*hed 7 state-management flutter flutter-bloc
上下文:这里的页面可以TabView
在所有这些选项卡使用的选项卡之间导航flutter_bloc
(版本 6.0.1)。
问题:当滑动到任何选项卡时,状态不会被保留,整个小部件树正在重建,如下面的 gif 所示
这是build()
方法:
@override
Widget build(BuildContext context) {
super.build(context);
return DefaultTabController(
initialIndex: 0,
length: 3,
child: Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBarWithTabs(),
body: TabBarView(
children: <Widget>[
defaultViewforCategory(1), //Women
defaultViewforCategory(3), //Men
defaultViewforCategory(2), //Kids
],
),
),
);
}
Run Code Online (Sandbox Code Playgroud)
下面是函数的实现 defaultViewforCategory()
Widget defaultViewforCategory(int mainCategoryId) {
return PageStorage(
bucket: bucket,
key: PageStorageKey(mainCategoryId),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 1200),
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 150),
child: Container(
height: 800,
child: RefreshIndicator(
onRefresh: () => refreshTimeline(),
child: CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
SliverToBoxAdapter(
child: MasonryGrid(
column: getResponsiveColumnNumber(context, 1, 2, 6),
children: <Widget>[
// First Bloc
BlocProvider(
create: (context) {
BrandBloc(repository: _brandRepository);
},
child: Container(
width: 200,
alignment: Alignment.center,
height: 90,
child: BrandScreen(
brandBloc: context.bloc(),
),
),
),
CategoryScreen(
// Second Bloc
categoryBloc: CategoryBloc(
mainCategoryId: mainCategoryId,
repository: _categoryRepository),
),
// -------------- Featured Items--------------------------
Container(
width: 200,
alignment: Alignment.center,
height: 350,
child: _buildFeaturedItemsList(mainCategoryId),
),
Placeholder(strokeWidth: 0, color: Colors.white)
],
),
),
],
),
),
),
),
],
),
),
);
}
Run Code Online (Sandbox Code Playgroud)
尝试过的解决方案:
1 - 我尝试过,AutomaticKeepAliveClientMixin
但结果证明mixin
在使用BottomNavigationBar
.
2 -PageStorage
没有解决问题。
问题:如何阻止TabView
每次用户滑动到另一个选项卡时重建?
正如您所说,问题之一是TabBarView
每次显示选项卡时都会重建。对于这个问题,这里是一个开放的话题。因此,每次屏幕更改时都会创建一个全新的 Bloc 实例。
注意由于CategoryBloc
未通过使用,BlocProvider
您应该手动处置该块。
这里一个简单的解决方案是将BlocProvider
层次结构中的向上移动到TabBarView
构建方法中的第一个组件之外。
注意从性能角度来看,这是可以的,因为当请求块时,BLOC 会被延迟初始化。
现在更微妙的问题是创建的方式CategoryBloc
(因为有一个动态构造函数)。这里你可以有两种解决方案:
要么您将CategoryBloc
屏幕修改为可由所有类别共享 - 在这里我无法为您提供太多帮助,因为我没有它的代码。这个想法是mainCategoryId
通过结果发送新状态events
。emits
在这种情况下,您应该将 转发到mainCategoryId
,state
并且仅当匹配 CategoryScreen id(可以在创建屏幕时传递)时才BlocBuilder
使用buildWhen
参数进行构建。并且不要忘记在子级之外mainCategoryId
提供使用的 CategoryBloc 。BlocProvider
TabBarView
或者将 CategoryBloc 创建移到 TabBarView 之外并缓存它们以供进一步访问。我在下面创建了一个例子来强调这一点。
// ...
///
/// Categories blocs cache.
///
Map<int, CategoryBloc> _categoriesBlocs;
///
/// Creates UNIQUE instances of CategoryBloc by id.
///
CategoryBloc getCategoryBlocById(int id) {
// If you don't already have a bloc for that particular id, create a new one
// and cache it (by saving it in the Map)
this._categoriesBlocs.putIfAbsent(
id,
() => CategoryBloc(
mainCategoryId: id,
repository: _categoryRepository,
));
// Return the cached category bloc
return this._categoriesBlocs[id];
}
///
/// This is very important. Because we manually create the BLOCs we have
/// to manually dispose them
///
@override
void dispose() {
for (var bloc in this._categoriesBlocs) {
bloc.displose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => BrandBloc(repository: _brandRepository),
)
],
child: DefaultTabController(
initialIndex: 0,
length: 3,
child: Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBarWithTabs(),
body: TabBarView(
children: <Widget>[
defaultViewforCategory(1), //Women
defaultViewforCategory(3), //Men
defaultViewforCategory(2), //Kids
],
),
),
),
);
}
// ...
CategoryScreen(
// Second Bloc
// Now, here you will get the same BLOC instance every time
categoryBloc: getCategoryBlocById(mainCategoryId),
),
// ...
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
87 次 |
最近记录: |