之前写过一篇文章叫"完美解决flutter 动态TabBar TabView的坑" ,希望对各位客官有所有帮助.今天我们再来深挖TabView.
可能各位觉得 本人是不是与TabView扛上了,其实不是的,是项目需要喽;
在看了之前那篇动态Tab TabView的文章后,会解决动态Tab,但紧接着就遇到,TabView里面的内容,如何保持状态呢.本人也在网上搜索一下解决方案,虽然有是有,但我发现要么是还不够详细,要么就是对动态Tab,TabView怎么保持状态这块没有相应的介绍,对于flutter 新手来说,可能还是难度的.这就是写这篇文章的初衷了.
好了,说不多说,先来看一下最终的效果.
1.固定个数的Tab (留意图片中滚动到的行数.比喻英语先是滚到了200行,等操作一段时间,再回来英语界面,还是在200行那个位置,也就是状态被保持了; 下面2张效果图同理)
2.动态Tab
3.动态Tab,每个TabView里面的数据不相同
固定个数的Tab
- 先新建一个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 = ['语文', '英语', '数学'];
final List<String> _contentList = [
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
];
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;
}
重点来喽
chinese_page, english_page, math_page 三个界面的代码都比较简单,关键的每个界面都是 with AutomaticKeepAliveClientMixin 以及 重写了 bool get wantKeepAlive => true;这个方法. 这就是状态保持的关键地方
写到这里是不是感觉此文章就应该结束了呢,其实不是的, 在项目中很有可能tab的个数是不确定,比喻说,tab个数是网络请求下来的数据,这就有了动态tab,接下来,我们介绍动态tab怎么保持状态
动态Tab
- 先新建一个tab_page (这个tab_page与前面有点区别)
- 再新建一个math_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 = [
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济'
];
final List<String> _contentList = [
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
];
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: //动态Tab
createSameContentPages(_tabValues)),
);
}
//创建与tabs个数相同的 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;
}
跑起来试试吧,与前面的效果图第二张图运行是一样的结果.
动态Tab 每个TabView里面的数据不相同
- 先新建一个tab_page (这个tab_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 = [
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济'
];
final List<String> _contentList = [
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
'语文',
'英语',
'化学',
'物理',
'数学',
'生物',
'体育',
'经济',
];
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: //动态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))); //传入不同的数据
} else if (i == 1) {
desList.add(ChinesePage(contentList.sublist(0, 5))); //传入不同的数据
} else {
desList.add(ChinesePage(contentList)); //传入不同的数据
}
}
return desList;
}
}
_tabValues 这个list可以是网络请求下来的数据.我这里是直接写死的,总体意思是根据_tabValues的个数来生成对应个数的pages,而且能保持各个page的状态;
跑起来试试吧,与前面的效果图第三张图运行是一样的结果.
结尾
希望这篇干货,对大家有所帮助吧,后续会分享更多干货,也希望大家多支持--不妨点个赞吧~~