flutter - Flutter:TabBarView 移动到一个选项卡也会重建其他选项卡
问题描述
我使用TabBarView
并注意到一些非常奇怪的东西。我在所有选项卡的小部件中放置了一些打印消息,以便在滑动选项卡时获得反馈。我得到了这些结果:
- 从 0 -> 1:调用 Tab 1,调用 Tab 3,调用 Tab 4,调用 Tab 0。
- 从 1 -> 2:调用 Tab 2,调用 Tab 2,调用 Tab 1,调用 Tab 3,调用 Tab 4,调用 Tab 2。
- 从 2 -> 3:调用 Tab 1,调用 Tab 3,调用 Tab 4,调用 Tab 2。
- 从 3 -> 4:调用 Tab 1,调用 Tab 3,调用 Tab 4。
真是奇怪的事情。它实际上重建(调用setState
)一个选项卡,即使它没有被选中。请记住,只有 Tab 0 和 Tab 2 里面有实际内容,其他的有空容器。
这是我的代码:
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
final AuthService _authService = AuthService();
final colors = [
Colors.red,
Colors.lightGreen,
Colors.blue,
Colors.amber,
Colors.deepPurpleAccent
];
Color scaffoldColor = Colors.red;
TabController _controller;
@override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 5);
_controller.addListener(() {
if (_controller.indexIsChanging) {
print("index is changing");
} else {
setState(() {
scaffoldColor = colors[_controller.index];
});
}
});
_controller.index = 1;
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 5,
child: Scaffold(
backgroundColor: scaffoldColor,
appBar: AppBar(
backgroundColor: scaffoldColor,
leading: IconButton(
icon: Icon(Icons.menu),
color: Colors.white,
onPressed: () {},
),
elevation: 0,
title: Text(
'HOME Screen',
style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
),
actions: [
FlatButton.icon(
onPressed: () async {
await _authService.signOut();
},
icon: Icon(Icons.exit_to_app),
label: Text('Log out'),
),
],
bottom: TabBar(
isScrollable: true,
controller: _controller,
indicatorWeight: 6,
indicatorColor: Colors.transparent,
tabs: <Widget>[
Tab(
child: Container(
child: Text(
'Chats',
style: TextStyle(
color:
_controller.index == 0 ? Colors.white : Colors.grey,
fontSize: 18),
),
),
),
Tab(
child: Container(
child: Text(
'Online',
style: TextStyle(
color:
_controller.index == 1 ? Colors.white : Colors.grey,
fontSize: 18),
),
),
),
Tab(
child: Container(
child: Text(
'Discover',
style: TextStyle(
color:
_controller.index == 2 ? Colors.white : Colors.grey,
fontSize: 18),
),
),
),
Tab(
child: Container(
child: Text(
'NULL',
style: TextStyle(
color:
_controller.index == 3 ? Colors.white : Colors.grey,
fontSize: 18),
),
),
),
Tab(
child: Container(
child: Text(
'NULL2',
style: TextStyle(
color:
_controller.index == 4 ? Colors.white : Colors.grey,
fontSize: 18),
),
),
),
],
),
),
body: TabBarView(
controller: _controller,
children: <Widget>[
Column(
children: <Widget>[
//CategorySelector(),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).accentColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
child: Column(
children: <Widget>[
FavoriteContacts4(),
RecentChats(),
],
),
),
),
],
),
Tab1(),
Column(
children: <Widget>[
//CategorySelector(),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).accentColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
child: SuggestedUsers(),
),
),
],
),
Tab3(),
Tab4(),
],
),
),
);
}
Widget tmpWidget(int i) {
print("Tab " + i.toString() + " is called");
return Text("Number" + i.toString());
}
}
这真的很烦人,因为每次我切换(或几乎)到另一个选项卡时,它都会调用 tab2 中的 api。我认为这与控制器有关!
更新:
即使我已将AutomaticKeepAliveClientMixin
每个Statefull
选项卡小部件放入其中,也会进行重建。例如,当我从 Tab3 滑动到 Tab4 时,所有选项卡都将被重建。Tab1,2,3,4 全部。
这是我为 Tab 1,3 和 4 放置的代码。Tab 0 和 2 有其他小部件,但作用相同。
class Tab1 extends StatefulWidget {
@override
_Tab1State createState() => _Tab1State();
}
class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context);
print("Tab 1 Has been built");
return Text("TAB 1");
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
解决方案
那是因为您正在调用setState({})
这意味着您的build
方法将被调用,并且由于您的所有方法都tabs
在同一个build
方法中,所有这些方法都将被重新创建。为了解决这个问题,您必须:
StatefulWidget
为每个孩子创建TabBarView
- 让你的
StatefulWidget
扩展AutomaticKeepAliveClientMixin
(class ExampleState extends State<Example> with AutomaticKeepAliveClientMixin
- 你必须覆盖
wantKeepAlive
:@override bool get wantKeepAlive => true;
- 在您的方法
super.build(context)
中作为第一行调用build
这将防止每次重新构建您的小部件
推荐阅读
- sql - 在 Spark-SQL 中为 Azure Databricks 创建用户定义(非临时)函数
- ios - 使用 swift 4 从 ios 监听 Firestore 中的实时更新
- android - UPI 隐式意图选择器在红米设备上不起作用
- spring-boot - Spring Boot,获取用于将数据库提取映射到 POJO 的查询
- bash - Bash shellscript 数组元素无序
- c# - 演员词典
到 IReadOnlyDictionary ? - javascript - 呈现可编辑表格的最佳方式
- sql - 如何在 BigQuery 中构建报告的热门转化路径
- android - 清除 sharedViewModel
- xml - XSL - 使用 select 检查多个参数