支持左右滑动切换、不限 item 数量的 tabbar 是分类信息列表展示必不可少的组件,在 flutter 中可通过 AppBar TabBar PageView ListView 完成这个需求
TabBar 部件
支持修改 tab 背景颜色、底部横线颜色,tab 上的按钮样式以及对应切换的页面,可通过 List 传入,这样可以支持更多拓展需求
代码语言:javascript复制import 'package:delongzhixuan/main/tab/MainTab.dart';
import 'package:flutter/material.dart';
/**
* @des 顶部 tab 部件
* @author liyongli 20190704
* */
class TabWidget extends StatefulWidget{
// item 组件
List<Widget> tabItems;
// item 组件对应的 widget
List<Widget> tabItemWidgets;
// tab 的背景颜色
Color backgroundColor;
// item 底部横线颜色
Color indicatorColor;
// item 对应的 widget 控制器
PageController pageController;
TabWidget({
@required this.tabItems,
@required this.tabItemWidgets,
this.backgroundColor,
this.indicatorColor,
this.pageController
}):super();
@override
State<StatefulWidget> createState() => _TabWidgetState();
}
/**
* @des 顶部 tab 部件 State
* @author liyongli 20190704
* */
class _TabWidgetState extends State<TabWidget> with SingleTickerProviderStateMixin{
TabController tabController;
@override
void initState() {
super.initState();
tabController = new TabController(length: widget.tabItems.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// 顶部 TabBar
title: Text(MainTabState.pageNameList[1], style: MainTabState.appbarTestStyle),
backgroundColor: MainTabState.appbarBackgroundColor,
centerTitle: true,
bottom: TabBar(
isScrollable: true, // 设置是否支持左右滑动
controller: tabController, // 控制器
indicatorColor: widget.indicatorColor, // item 底部横线颜色
tabs: widget.tabItems, // 设置列表内容
),
),
// TabBar 对应的 widget
body: new PageView(
controller: widget.pageController,
children: widget.tabItemWidgets,
onPageChanged: (index){
tabController.animateTo(index);
},
),
);
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
}
TabBar 部件 item 对应的页面
也就是 ListView 部分,修改 initPageWidget 返回的 widget 为你需要的样式即可
代码语言:javascript复制import 'package:flutter/material.dart';
/**
* @des 顶部 tab 部件对应的 widget
* @author liyongli 20190704
* */
class TabItemWidget extends StatefulWidget {
String itemIndex;
TabItemWidget(this.itemIndex);
@override
State<StatefulWidget> createState() => _TabItemWidgetState();
}
/**
* @des 顶部 tab 部件对应的 widget state
* @author liyongli 20190704
* */
class _TabItemWidgetState extends State<TabItemWidget> {
@override
Widget build(BuildContext context) {
return initPageWidget();
}
/**
* 初始化 page widget
* */
Widget initPageWidget(){
return ListView.builder(itemBuilder: (context, i){
return Container(
alignment: Alignment.center,
width: double.maxFinite,
height: 100.0,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xff000000), width: 0.2))
),
child: Text("${widget.itemIndex} - $i", style: TextStyle(color: Color(0xff000000), fontSize: 20.0),),
);
});
}
}
TabBar 部件如何应用
代码语言:javascript复制import 'package:delongzhixuan/utils/tab/TabWidget.dart';
import 'package:delongzhixuan/utils/tab/TabItemWidget.dart';
import 'package:flutter/material.dart';
/**
* @des 产品首页
* @author liyongli 20190704
* */
class MainProduct extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MainProductState();
}
/**
* @des 产品首页 State
* @author liyongli 20190704
* */
class _MainProductState extends State<MainProduct> {
// 控制器
PageController pageController;
// 模拟数据
List<String> items = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10",];
// tabbar 按钮集合
List<Widget> tabItems = new List<Widget>();
// tabbar 按钮对应的页面集合
List<Widget> tabItemWidgets = new List<Widget>();
@override
void initState() {
super.initState();
pageController = new PageController();
tabItems = _initTabItems(items, tabItems, false);
tabItemWidgets = _initTabItemWidgets(items, tabItemWidgets);
setState(() { });
}
@override
Widget build(BuildContext context) {
return _initPageWidget(context);
}
/**
* 初始化 page widget
* */
Widget _initPageWidget(BuildContext context){
return new TabWidget(
tabItems: tabItems,
tabItemWidgets: tabItemWidgets,
pageController: pageController,
indicatorColor: Colors.yellow,
);
}
/**
* 初始化 tab item 部件
*
* @params itemNameList 存储 tab item 名字的集合
* @params itemWidgetList 转化完成后返回的集合
* @params clear 是否需要在转化开始前,先行清空返回数组内的数据,主要用于应对分页加载刷新时的场景
*
* @return 已完成转化的 widget 集合
* */
List<Widget> _initTabItems(List<String> itemNameList, List<Widget> itemWidgetList, bool clear){
// 检查传入的名字集合是否有数据,若没有数据则 return null
if(null == itemNameList || itemNameList.length < 1){
return null;
}
// 检查目标集合是否为空,为空则创建
if(null == itemWidgetList){
itemWidgetList = new List<Widget>();
}
// 检查是否需要先行清空 widget 集合数据
if(clear && itemWidgetList.length > 0){
itemWidgetList.clear();
}
// 开始转化
for(var i = 0 ; i < itemNameList.length ; i ){
itemWidgetList.add(
new FlatButton(
onPressed: (){pageController.jumpTo(MediaQuery.of(context).size.width * i);},
child: Text(itemNameList[i], style: TextStyle(color: Color(0xffffffff)),)
)
);
}
return itemWidgetList;
}
/**
* 初始化 tab item 对应的 widget(ListView 列表)
*
* @params itemNameList 存储 tab item 名字的集合
* @params itemWidgetList 转化完成后返回的集合
*
* @return 已完成初始化的 tab item 对应的 widget 的数据集合
* */
List<Widget> _initTabItemWidgets(List<String> itemNameList, List<Widget> itemWidgetList){
// 检查传入的名字集合是否有数据,若没有数据则 return null
if(null == itemNameList || itemNameList.length < 1){
return null;
}
// 检查目标集合是否为空,为空则创建
if(null == itemWidgetList){
itemWidgetList = new List<Widget>();
}
// 开始创建
for(var i = 0 ; i < itemNameList.length ; i ){
itemWidgetList.add(new TabItemWidget(itemNameList[i]));
}
return itemWidgetList;
}
}