17.请求数据保留

前言

前文中可以发现一个问题,每次切换页面,都会重新请求数据。而实际开发中,我们会对数据进行保留,在需要的时候再进行数据更新。

Mixin

调整继承关系

多继承 AutomaticKeepAliveClientMixin

class MessagePage extends StatefulWidget {
  @override
  _MessagePageState createState() => _MessagePageState();
}

class _MessagePageState extends State<MessagePage> with AutomaticKeepAliveClientMixin<MessagePage> {
    ...
}

重写 wantKeepAlive

class _MessagePageState extends State<MessagePage> with AutomaticKeepAliveClientMixin<MessagePage> {
    ...

    @override
    bool get wantKeepAlive => true;
}

调整 build 方法

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(...);
  }

调整 MyHomePage (标签Tab页)

原先我们的切换Tab的逻辑是这样的:

class _MyHomePageDataSource extends State<MyHomePage> {
  int _selectedTab = 0;
  final List<Widget> _pages = [
      MessagePage(), 
      ContactsPage(), 
      MommentPage(), 
      MinePage()
      ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_selectedTab],
      ...
    );

并非所有的子页面的 widget 都在标签容器的 widget 树中,导致每次切换都会去重新生成渲染。

  • 我们需要做如下调整:

    • 构建 PageController

    • 调整 BodyPageView, 并绑定 PageControllerpages

    • 通过 PageController 切换子页面

class _MyHomePageDataSource extends State<MyHomePage> {
  int _selectedTab = 0;
  final List<Widget> _pages = [
    MessagePage(),
    ContactsPage(),
    MommentPage(),
    MinePage()
  ];
  // 一、 构建 PageController
  final PageController _pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        // 二、 调整 Body 为 PageView, 并绑定 PageController 和 pages
      body: PageView(
        controller: _pageController,
        children: _pages,
      ),
      bottomNavigationBar: BottomNavigationBar(
        selectedItemColor: Colors.green,
        unselectedItemColor: Colors.grey,
        currentIndex: _selectedTab,
        onTap: (idx) {
          setState(() {
            _selectedTab = idx;
            // 三、 通过 PageController 切换子页面
            _pageController.jumpToPage(_selectedTab);
          });
        },
        items: const [...],
      ),
    );
  }
}

检查效果

PageView

滑动切换子页面

在使用总突然发现可以通过滑动切换 PageView 的子页面。但是底部的标签选中没有变化,下面我们来处理一下。

同步标签切换

通过 onPageChanged 来监听页面的切换,同步修改选中标签。

body: PageView(
        onPageChanged: (idx) {
          setState(() {
            _selectedTab = idx;
          });
        },
        controller: _pageController,
        children: _pages,
      ),

关闭滑动切换

当然,不需要滑动的话可以通过 physics 来进行关闭。

body: PageView(
    physics: const NeverScrollableScrollPhysics(),
    controller: _pageController,
    children: _pages,
),

Last updated