学习视频地址:https://www.bilibili.com/video/BV1S4411E7LY?p=37&vd_source=cee744cae4ead27f8193fc7904647073
学习笔记
本篇基于Flutter学习笔记15和17,Flutter学习笔记15使用了BottomNavigationBar,Flutter学习笔记17使用了TabBar,本节则是将二者结合起来。
在开始前,你需要根据学习笔记15搭建起一个拥有5个tab的页面
并将学习笔记17中的HomePage放到./tabs/home.dart中
运行起来
实在是太丑了,本节就要在此基础上给美美容。
1.去掉home页面的appbar
直接将TabBar放到AppBar的title部分
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: TabBar(
tabs: [Text("推荐"), Text("新闻"), Text("视频")],
controller: _tabController,
isScrollable: true,
indicatorColor: Colors.red,
indicatorWeight: 10,
indicatorSize: TabBarIndicatorSize.tab,
// indicatorPadding: EdgeInsets.all(2),
labelColor: Colors.black,
labelStyle: TextStyle(fontSize: 20),
unselectedLabelColor: Colors.white,
unselectedLabelStyle: TextStyle(fontSize: 10),
),
backgroundColor: Colors.green,
),
body: TabBarView(
controller: _tabController,
children: [Text("推荐"), Text("新闻"), Text("视频")],
),
);
}
}
看效果
2.太高了?使用PreferredSize组件改变appbar高度
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(40),
child: AppBar(
centerTitle: true,
title: TabBar(
tabs: [Text("推荐"), Text("新闻"), Text("视频")],
controller: _tabController,
isScrollable: true,
indicatorColor: Colors.red,
// indicatorWeight: 10,
indicatorSize: TabBarIndicatorSize.label,
// indicatorPadding: EdgeInsets.all(2),
labelColor: Colors.red,
// labelStyle: TextStyle(fontSize: 20),
unselectedLabelColor: Colors.black,
// unselectedLabelStyle: TextStyle(fontSize: 0),
),
backgroundColor: Colors.white,
),
),
body: TabBarView(
controller: _tabController,
children: [Text("推荐"), Text("新闻"), Text("视频")],
),
);
}
}
显示效果
3.自定义KeepAliveWrapper实现缓存页面
import 'package:flutter/material.dart';
class KeepAliveWrapper extends StatefulWidget {
final Widget? child; //必须传子控件
final bool keepAlive; //是否缓存
const KeepAliveWrapper(
{Key? key, this.child, this.keepAlive = true})
: super(key: key);
_KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
Widget build(BuildContext context) {
return widget.child!; //
}
// TODO: implement wantKeepAlive
bool get wantKeepAlive => widget.keepAlive;
}
用法:
这里的缓存的意思是:当页面被切换回来时,还能保持之前的状态。
body: TabBarView(
controller: _tabController,
children: [
KeepAliveWrapper(
child: ListView(
children: [
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表1"),
),
ListTile(
title: Text("我是列表5"),
),
ListTile(
title: Text("我是列表4"),
),
ListTile(
title: Text("我是列表3"),
),
],
),
),
Text("新闻"),
Text("视频")
],
),
我用KeepAliveWrapper包裹了一下推荐界面的ListView,这样Listview被划出界面,再被划回界面时,还会保持上次的滚动位置。
4.监听当前打开的是哪个tab
在_HomePageState的initState方法里给tabcontroller添加监听事件
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
_tabController.addListener(() {
print(_tabController.index);
});
}
得到的结果却是
切换页面时,会一下子输出两个一样的index
当点击tab时,会输出一个index,然后tab开始滚动到你所点击的位置,又会输出一个。
所以我需要给打印方法加点条件
_tabController.addListener(() {
// ! 类型断言,表示肯定不为空
if (_tabController.animation!.value == _tabController.index) {
print(_tabController.index);
}
});
此时,只有切换滚动动画结束,才会输出index
5.最后,销毁资源
void dispose() {
super.dispose();
_tabController.dispose();
}