完美解決flutter Tab/TabBar切換, TabView 頁面狀態(tài)保持

之前寫過一篇文章叫"完美解決flutter 動(dòng)態(tài)TabBar TabView的坑" ,希望對(duì)各位客官有所有幫助.今天我們?cè)賮砩钔赥abView.
可能各位覺得 本人是不是與TabView扛上了,其實(shí)不是的,是項(xiàng)目需要嘍;

在看了之前那篇?jiǎng)討B(tài)Tab TabView的文章后,會(huì)解決動(dòng)態(tài)Tab,但緊接著就遇到,TabView里面的內(nèi)容,如何保持狀態(tài)呢.本人也在網(wǎng)上搜索一下解決方案,雖然有是有,但我發(fā)現(xiàn)要么是還不夠詳細(xì),要么就是對(duì)動(dòng)態(tài)Tab,TabView怎么保持狀態(tài)這塊沒有相應(yīng)的介紹,對(duì)于flutter 新手來說,可能還是難度的.這就是寫這篇文章的初衷了.

好了,說不多說,先來看一下最終的效果.

1.固定個(gè)數(shù)的Tab (留意圖片中滾動(dòng)到的行數(shù).比喻英語先是滾到了200行,等操作一段時(shí)間,再回來英語界面,還是在200行那個(gè)位置,也就是狀態(tài)被保持了; 下面2張效果圖同理)


文件.gif

2.動(dòng)態(tài)Tab


文件 (1).gif

3.動(dòng)態(tài)Tab,每個(gè)TabView里面的數(shù)據(jù)不相同

2.gif

固定個(gè)數(shù)的Tab

  • 先新建一個(gè)tab_page
  • 再分別建立 chinese_page, english_page, math_page

tab_page 代碼如下:

import 'package:flutter/material.dart';
import 'package:flutter_test_demos/chinese_page.dart';
import 'english_page.dart';
import 'package:flutter_test_demos/math_page.dart';

class TabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TabBar();
}

class _TabBar extends State<TabPage> {
  final List<String> _tabValues = ['語文', '英語', '數(shù)學(xué)'];

  final List<String> _contentList = [
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
  ];

  TabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TabController(
      length: _tabValues.length,
      vsync: ScrollableState(),
    );
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('TabBar'),
        bottom: TabBar(
          tabs: _tabValues.map((f) {
            return Text(f);
          }).toList(),
          controller: _controller,
          indicatorColor: Colors.red,
          indicatorSize: TabBarIndicatorSize.tab,
          isScrollable: true,
          labelColor: Colors.red,
          unselectedLabelColor: Colors.black,
          indicatorWeight: 5.0,
          labelStyle: TextStyle(height: 2),
        ),
      ),
      body: TabBarView(controller: _controller, children: [
        ChinesePage(_contentList),
        EnglisthPage(),
        MathPage()
      ] //固定Tab

          ),
    );
  }
}

chinese_page 代碼如下:

import 'package:flutter/material.dart';

class ChinesePage extends StatefulWidget {
  List list;
  ChinesePage(this.list);
  @override
  _ChinesePageState createState() => _ChinesePageState();
}

class _ChinesePageState extends State<ChinesePage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: ListView.builder(
            itemCount: widget.list.length,
            itemBuilder: (build, index) {
              return Container(
                  padding: EdgeInsets.only(top: 150),
                  child: Text("${widget.list[index]} ----- $index"));
            }));
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

english_page 代碼如下:

import 'package:flutter/material.dart';

class EnglisthPage extends StatefulWidget {
  @override
  _EnglisthPageState createState() => _EnglisthPageState();
}

class _EnglisthPageState extends State<EnglisthPage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: ListView.builder(itemBuilder: (build, index) {
      return Text("en --- $index");
    }));
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

math_page 代碼如下:

import 'package:flutter/material.dart';

class MathPage extends StatefulWidget {
//  String title;
//  MathPage(this.title);
  @override
  _MathPageState createState() => _MathPageState();
}

class _MathPageState extends State<MathPage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: ListView.builder(itemBuilder: (build, index) {
      return Text("math --- $index");
    }));
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

重點(diǎn)來嘍

chinese_page, english_page, math_page 三個(gè)界面的代碼都比較簡(jiǎn)單,關(guān)鍵的每個(gè)界面都是 with AutomaticKeepAliveClientMixin 以及 重寫了 bool get wantKeepAlive => true;這個(gè)方法. 這就是狀態(tài)保持的關(guān)鍵地方

寫到這里是不是感覺此文章就應(yīng)該結(jié)束了呢,其實(shí)不是的, 在項(xiàng)目中很有可能tab的個(gè)數(shù)是不確定,比喻說,tab個(gè)數(shù)是網(wǎng)絡(luò)請(qǐng)求下來的數(shù)據(jù),這就有了動(dòng)態(tài)tab,接下來,我們介紹動(dòng)態(tài)tab怎么保持狀態(tài)

動(dòng)態(tài)Tab

  • 先新建一個(gè)tab_page (這個(gè)tab_page與前面有點(diǎn)區(qū)別)
  • 再新建一個(gè)math_page (這個(gè)math_page與前面有點(diǎn)區(qū)別)
    tab_page 代碼如下:
import 'package:flutter/material.dart';
import 'package:flutter_test_demos/chinese_page.dart';
import 'english_page.dart';
import 'package:flutter_test_demos/math_page.dart';

class TabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TabBar();
}

class _TabBar extends State<TabPage> {
  final List<String> _tabValues = [
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)'
  ];
  final List<String> _contentList = [
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
  ];

  TabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TabController(
      length: _tabValues.length,
      vsync: ScrollableState(),
    );
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('TabBar'),
        bottom: TabBar(
          tabs: _tabValues.map((f) {
            return Text(f);
          }).toList(),
          controller: _controller,
          indicatorColor: Colors.red,
          indicatorSize: TabBarIndicatorSize.tab,
          isScrollable: true,
          labelColor: Colors.red,
          unselectedLabelColor: Colors.black,
          indicatorWeight: 5.0,
          labelStyle: TextStyle(height: 2),
        ),
      ),
      body: TabBarView(
          controller: _controller,
          children: //動(dòng)態(tài)Tab
              createSameContentPages(_tabValues)),
    );
  }

  //創(chuàng)建與tabs個(gè)數(shù)相同的 Pages
  List<Widget> createSameContentPages(List tabList) {
    List<Widget> desList = [];
    for (int i = 0; i < tabList.length; i++) {
      desList.add(MathPage(tabList[i]));
    }
    return desList;
  }
}

math_page 代碼如下:

import 'package:flutter/material.dart';

class MathPage extends StatefulWidget {
  String title;
  MathPage(this.title);
  @override
  _MathPageState createState() => _MathPageState();
}

class _MathPageState extends State<MathPage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: ListView.builder(itemBuilder: (build, index) {
      return Text("${widget.title} --- $index");
    }));
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

跑起來試試吧,與前面的效果圖第二張圖運(yùn)行是一樣的結(jié)果.

動(dòng)態(tài)Tab 每個(gè)TabView里面的數(shù)據(jù)不相同

  • 先新建一個(gè)tab_page (這個(gè)tab_page與前面有點(diǎn)區(qū)別)
    tab_page 代碼如下:
import 'package:flutter/material.dart';
import 'package:flutter_test_demos/chinese_page.dart';
import 'english_page.dart';
import 'package:flutter_test_demos/math_page.dart';

class TabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TabBar();
}

class _TabBar extends State<TabPage> {
  final List<String> _tabValues = [
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)'
  ];
  final List<String> _contentList = [
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
    '語文',
    '英語',
    '化學(xué)',
    '物理',
    '數(shù)學(xué)',
    '生物',
    '體育',
    '經(jīng)濟(jì)',
  ];

  TabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TabController(
      length: _tabValues.length,
      vsync: ScrollableState(),
    );
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('TabBar'),
        bottom: TabBar(
          tabs: _tabValues.map((f) {
            return Text(f);
          }).toList(),
          controller: _controller,
          indicatorColor: Colors.red,
          indicatorSize: TabBarIndicatorSize.tab,
          isScrollable: true,
          labelColor: Colors.red,
          unselectedLabelColor: Colors.black,
          indicatorWeight: 5.0,
          labelStyle: TextStyle(height: 2),
        ),
      ),
      body: TabBarView(
          controller: _controller,
          children: //動(dòng)態(tài)Tab
              createPages(_contentList, _tabValues)),
    );
  }

  List<Widget> createPages(List contentList, List tabList) {
    List<Widget> desList = [];
    for (int i = 0; i < tabList.length; i++) {
      if (i == 0) {
        desList.add(ChinesePage(contentList.sublist(0, 10))); //傳入不同的數(shù)據(jù)
      } else if (i == 1) {
        desList.add(ChinesePage(contentList.sublist(0, 5))); //傳入不同的數(shù)據(jù)

      } else {
        desList.add(ChinesePage(contentList)); //傳入不同的數(shù)據(jù)
      }
    }
    return desList;
  }
}

_tabValues 這個(gè)list可以是網(wǎng)絡(luò)請(qǐng)求下來的數(shù)據(jù).我這里是直接寫死的,總體意思是根據(jù)_tabValues的個(gè)數(shù)來生成對(duì)應(yīng)個(gè)數(shù)的pages,而且能保持各個(gè)page的狀態(tài);
跑起來試試吧,與前面的效果圖第三張圖運(yùn)行是一樣的結(jié)果.

結(jié)尾

希望這篇干貨,對(duì)大家有所幫助吧,后續(xù)會(huì)分享更多干貨,也希望大家多支持--不妨點(diǎn)個(gè)贊吧~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容