场景.
app 有四个模块, A, B, C, D 四个页面分别是四个模块的首页, iOS 的常规操作是 TabBar 有4个 item, 四个首页不销毁, 即: A 切换到 B , B 切换到 A, A 页面不会被重新加载并渲染.
但是 Flutter 不同, 因为 Flutter 是一个高效渲染引擎, A 切换到 B 时, A 页面就会被渲染抛弃, A 页面就脱离了渲染树, 再次 B 切换到 A 时, 被重新加载. 重新请求数据, 重新渲染, 这显然是不可取的. 那么我们怎么保证不被重新加载,渲染呢 ? 就要满足以下三点.
页面状态保持活跃的三个必要条件:
1. 保证各个页面在切换到其他页面时, 不会脱离渲染树.
那么 A, B, C, D 四个页面就需要一个 PageView 持有他们, 这样才能保证不会离开渲染树,
此处只展示关键代码
- 记录四个页面的数组
List<Widget> _pages = [ChatPage(), FriendsPage(), DiscoverPage(), MinePage()];
- 页面间跳转的控制器
// 默认在第一个页面, 即 ChatPage
final PageController _controller = PageController(initialPage: 0);
- pageview 作为 Scaffold 的 body, 各模块首页之间的切换习惯是点击底部的 tab item. 所以此处禁用页面滚动. 页面滚动时会触发 onPageChanged 回调.
PageView(
controller: _controller,
children: _pages,
// 禁止页面左右滚动,
physics: NeverScrollableScrollPhysics(),
// 页面左右滚动触发的函数
// onPageChanged: (int index) {
// _currentIndex = index;
// setState(() {});
// },
)
- 在 Scaffold 的 bottomNavigationBar 属性中有个 onTap 回调函数, 当点击 item 时, 传回一个 index, 就是当前点击的下标 , _controller 调用 jumpToPage 即可切换到对应的页面
// 切换到 pageview 对应的页面
_controller.jumpToPage(_currentIndex);
2. A, B, C, D 四个页面必须必须是继承 StatefulWidget .
class ChatPage extends StatefulWidget {
@override
_ChatPageState createState() => _ChatPageState();
}
3. A, B, C, D 四个页面状态管理类混入状态保活 AutomaticKeepAliveClientMixin. 并实现一个保活状态 getter .
class ChatPage extends StatefulWidget {
@override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
}