前言
就以咱们平时比较常见的微信运用参阅,咱们比较常用的组件便是底部 tabbar
了,除此之外,便是顶部的类似于 tabbar
的组件了(有些当地叫顶部叫PageView
),两者吞并的,就以 app 主页为例,上下两个部分一望而知
事例demo地址(Tabbar文件夹)
下面就别离介绍这两种怎么运用的,以及怎么保存状况
底部tabbar
底部 tabbar
便是咱们常见的微信底部的切换功用作用,如下所示
其首要是依靠 BottomNavgationBar
、PageView
、PageController
,如下所示
class NormalTabBar extends StatefulWidget {
const NormalTabBar({Key? key}) : super(key: key);
@override
State<NormalTabBar> createState() => _NormalTabBarState();
}
class _NormalTabBarState extends State<NormalTabBar> {
//用于和谐tabbar和内容的联动
final PageController _controller = PageController(
initialPage: 0 //默以为0,能够不填写
);
//存放bottombar信息,防止编写过多重复ui代码
final List<TabBarItem> items = [
TabBarItem(title: '聊天', norImage: "images/tabbar_chat.png", selImage: "images/tabbar_chat_hl.png"),
TabBarItem(title: '联系人', norImage: "images/tabbar_contact.png", selImage: "images/tabbar_contact_hl.png"),
TabBarItem(title: '发现', norImage: "images/tabbar_discover.png", selImage: "images/tabbar_discover_hl.png"),
TabBarItem(title: '我的', norImage: "images/tabbar_mine.png", selImage: "images/tabbar_mine_hl.png")
];
int _pageIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
currentIndex: _pageIndex,
onTap: (int page) {
setState(() {
_pageIndex = page;
});
_controller.jumpToPage(page);
},
backgroundColor: Colors.white,
type: BottomNavigationBarType.fixed,
unselectedItemColor: Colors.black,
selectedItemColor: Colors.cyanAccent,
unselectedFontSize: 12,
selectedFontSize: 12,
items: items.map((e) {
return BottomNavigationBarItem(
label: e.title,
icon: Image.asset(e.norImage, width: 20, height: 20,),
activeIcon: Image.asset(e.selImage, width: 20, height: 20,),
);
}).toList(),
),
body: PageView(
controller: _controller,
//不设置默许能够左右活动,假如不想左右滑动如下设置,能够依据ios或者android来设置
physics: Platform.isAndroid ? const PageScrollPhysics() : const NeverScrollableScrollPhysics(),
children: const [
//设置内容页面即可,要和 bottomNavigationBar 数量共同
TabbarContainerView(color: Colors.yellow, name: '1',),
TabbarItemInAppBarView(color: Colors.cyanAccent, name: "2",),
TabbarContainerView(color: Colors.green, name: "3",),
TabbarItemInAppBarView(color: Colors.blueAccent, name: "4",),
],
),
);
}
}
顶部tabbar
顶部tabbar尽管没有底部那么常用,但是在不少app的一些场景也是用的不少,下面介绍下其运用,本质和tabbar
功用类似,只不过出了别的一个组件,花不说了,作用如下所示
其有两种方案,一种运用系统默许的,别的一种运用自定义的
默许顶部tabbar
完成首要经过 DefaultTabController
、TabBar
、TabBarView
,如下所示
class TabbarContainerView extends StatefulWidget {
final Color color;
final String name;
const TabbarContainerView({Key? key, required this.color, required this.name}) : super(key: key);
@override
State<TabbarContainerView> createState() => _TabbarContainerViewState();
}
//承继maxin AutomaticKeepAliveClientMixin 同时重写 wantKeepAlive 能够对当时页面状况保存,防止从头烘托初始化参数
class _TabbarContainerViewState extends State<TabbarContainerView> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
final List<String> tabNames = ["引荐", "订阅"];
@override
void initState() {
super.initState();
print(widget.name);
}
@override
Widget build(BuildContext context) {
super.build(context);
//经过 DefaultTabController 可主动调节内部tabbar联动
return DefaultTabController(
length: tabNames.length,
child: Scaffold(
appBar: AppBar(
title: const Text("带Tabs的tabbar子页面"),
//默许在下面放一排 Tab
bottom: TabBar(
//这个参数比较特别,默以为false,不出屏元素多了会被揉捏内容
//假如想支撑滚动,边内部揉捏,能够将此参数设置为true
//isScrollable: true,
//设置tabs标签
tabs: tabNames.map((e) => Tab(text: e,)).toList(),
),
),
//运用 TabBarView 来声明咱们的内容组件
body: TabBarView(
children: tabNames.map((e) {
return TabsContainer(
name: widget.name,
color: widget.color,
);
}).toList(),
),
),
);
}
}
自定义顶部tabbar
除了上面默许的一横框的 tabbar
之外,还有类似与淘宝主页的那种作用,这种也能够经过自定义tabbar
完成,如下所示(由于测试子页面多出来一个回来,所以居中有反常,正常不会有这这状况,依据状况自行调整即可)
其完成首要经过 TabController
、TabBarView
,而 bar
咱们自定义,经过 TabController
调节联动即可
其间 TabController
比较特别,需求集成自 SingleTickerProviderStateMixin
(由于多承继mixin
需求with
),然后推迟初始化 late
防止编译过错即可
class TabInfosItem {
final String name;
final int index;
bool selected;
TabInfosItem({
required this.name,
required this.selected,
required this.index
});
}
class TabbarItemInAppBarView extends StatefulWidget {
final Color color;
final String name;
const TabbarItemInAppBarView({Key? key, required this.color, required this.name}) : super(key: key);
@override
State<TabbarItemInAppBarView> createState() => _TabbarItemInAppBarViewState();
}
//承继 SingleTickerProviderStateMixin
class _TabbarItemInAppBarViewState extends State<TabbarItemInAppBarView> with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
@override
bool get wantKeepAlive => true;
List<TabInfosItem> tabs = [
TabInfosItem(name: "引荐", selected: true, index: 0),
TabInfosItem(name: "订阅", selected: false, index: 1),
];
//late 推迟初始化,防止报错,默许初始化是会呈现 this 指向不是对象的过错问题
late TabController _tabController;
@override
void initState() {
super.initState();
//初始化TabController
_tabController = TabController(length: tabs.length, vsync: this);
print(widget.name);
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
//由于有回来键,所以居中有问题这儿就不多设置了
appBar: AppBar(
title: Container(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: tabs.map((TabInfosItem item) {
return
//这儿就不多介绍了,增加额定参数,自定依据点击状况调整颜色线条等
//经过 tabController联动
TextButton(
onPressed: () {
_tabController.animateTo(item.index);
var tab = tabs.map((e) {
if (e.index == item.index) {
e.selected = true;
}else {
e.selected = false;
}
return e;
}).toList();
setState(() {});
},
child: Container(
width: 60,
alignment: Alignment.center,
child: Text(item.name, style: TextStyle(color: item.selected ? Colors.white : Colors.grey),),
),
);
}).toList(),
),
),
),
//TabBarView与默许的相同
body: TabBarView(
controller: _tabController,
children: tabs.map((e) {
return TabsContainer(
name: widget.name,
color: widget.color,
);
}).toList(),
),
);
}
}
看到上面是不是感觉底部tabbar也能够经过其定制了呢,没错,能够的,但为了减少代码和防止一些其他问题,还是运用系统的好一些,除非这儿默许的功用无法满足你的需求
保存状况 AutomaticKeepAliveClientMixin
前面的组件会看到许多都承继了 AutomaticKeepAliveClientMixin
,其便是一个保存状况的多承继 mixin 基类,由于默许运用 tabbar
会丢掉子组件状况,因而需求 AutomaticKeepAliveClientMixin
来进行保存状况,防止从头初始化,至于为什么会丢掉,跟系统完成有关系了
运用如下所示,承继后需求重写 wantKeepAlive
并且在 build
调用父类
方法
class _TabbarItemInAppBarViewState extends State<TabbarItemInAppBarView> with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
//需求重写该方法,回来为 true
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
//还需求调用super.build方法
super.build(context);
return container();
}
}
最后
这边文章能新手带来一些便利,内行忘了也能够参阅一下,我们一起学习前进哈