简介
原先的工程中用了TabBar
,最简单的那种。现在UI提出了优化要求,那么就要在原先的基础上进行样式修改。
选择:系统组件还是自定义?
-
使用系统提供的
TabBar
和TabBarView
套装 -
使用
Container
和ListView
等模拟
经过纠结,最终还是决定用TabBar
和TabBarView
套装,通过给出的属性来逐步达到目的;
使用
Container
和ListView
等模拟这种方式,实在没办法的时候再考虑;
-
TabBarView
只是一个容器,所以UI的难度集中在TabBar
TabBar常用属性
高度
从class TabBar extends StatefulWidget implements PreferredSizeWidget
可以看出,TabBar
是一种PreferredSizeWidget
。所以,可以考虑把TabBar
放到一个PreferredSize
组件中,高度就根据tabs
的数量来
@override
Widget build(BuildContext context) {
double height = 30.h;
if (tabs.length < 4) {
height = 44.h;
}
return PreferredSize(
preferredSize: Size.fromHeight(height),
child: TabBar(
tabs: tabs,
),
);
}
控制器
这个是TabBar
和TabBarView
联动的纽带,大多数情况是需要的,只需要按照原来的定义透传就可以了。
文本
-
颜色与其他样式分开设置;
-
选中与不选中分开设置;
this.labelColor,
this.labelStyle,
this.unselectedLabelColor,
this.unselectedLabelStyle,
滑动切换
这个默认是this.isScrollable = false,
;通常要改为true
文本间距
-
Tab底层应该是类似
ListView
的实现,等分是不大好做的; -
可以通过
labelPadding
这个属性模拟;tab少的时候大一些,tab多的时候小一些;
指示器大小
-
对应的属性是
indicatorSize
-
默认是和tab容器宽度一样
TabBarIndicatorSize.tab
-
按照设计图,这里要改为
TabBarIndicatorSize.label
, 和tab的文字一样长度;
指示器pad
-
对应的属性是
indicatorPadding
-
默认都是0,所以是和文字一样宽度,紧贴底部;
-
这里,按照设计图给一下就好;
-
另外,指示器和tab内容应该用了
stack
,两者不是一个图层。所以,设置indicatorPadding
可以改变指示器和文本之间的间距。
指示器形状
- 如果只是调整一下颜色和粗细,可以设置这两个属性
this.indicatorColor,
this.indicatorWeight = 2.0,
-
如果需要圆角,那么就需要使用
this.indicator
属性;同时,上面两个属性失效 -
this.indicator
的类型是Decoration
;但是这个是虚基类,真正有用的是UnderlineTabIndicator
indicator: UnderlineTabIndicator(
borderRadius: BorderRadius.circular(1.5.h),
borderSide: BorderSide(
color: const Color(0xFF11BA66),
width: 3.h,
),
),
tabs
-
类型定义是普通的
Widget
,final List<Widget> tabs;
-
但是,实际上一般都是给Tab组件
const Tab({
super.key,
this.text,
this.icon,
this.iconMargin = const EdgeInsets.only(bottom: 10.0),
this.height,
this.child,
})
-
从定义上看,可以是文字,也可以是图片,也可以是自定义
widget
;但是实际上,大多数情况是文本。 -
所以,这里简单处理,就是直接规定为文本
tabs: textList
.map((text) => Tab(
text: text,
))
.toList(),
封装为组件
由于Flutter的特性,就像套娃一样一层层嵌套。所以考虑在外面TabBar
外面套一层,把上面那些讨论过的属性定义封装起来。
class PandaTabBar extends StatelessWidget implements PreferredSizeWidget {
const PandaTabBar({
Key? key,
required this.textList,
this.controller,
}) : super(key: key);
final TabController? controller;
final List<String> textList;
@override
Widget build(BuildContext context) {
/// 参数判空
if (textList.isEmpty) {
return Container();
}
/// Tab个数4个以下,高度44;其他情况,高度30
/// 文本之间的间距,4个以下,40;其他情况15
double height = 30.h;
double pad = 15.w;
if (textList.length < 4) {
height = 44.h;
pad = 40.w;
}
return PreferredSize(
preferredSize: Size.fromHeight(height),
child: TabBar(
controller: controller,
labelColor: const Color(0xFF11BA66),
unselectedLabelColor: PandaColorConfig().col333333,
labelStyle: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
),
unselectedLabelStyle: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w400,
),
isScrollable: true,
labelPadding: EdgeInsets.symmetric(horizontal: pad),
indicatorSize: TabBarIndicatorSize.label,
indicatorPadding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 9.h),
indicator: UnderlineTabIndicator(
borderRadius: BorderRadius.circular(1.5.h),
borderSide: BorderSide(
color: const Color(0xFF11BA66),
width: 3.h,
),
),
tabs: textList
.map((text) => Tab(
text: text,
))
.toList(),
),
);
@override
Size get preferredSize => Size.fromHeight(44.h);
}
指示器固定大小
-
系统提供的指示器,宽度给了两种模式,和容器一样(加padding),或者和文字一样(加偏移)
-
指示器给出的是方角,不是圆角。
-
如果要求指示器固定宽度,并且是圆角,那么就需要自定义
UnderlineTabIndicator
-
做法也很取消,就是复制
UnderlineTabIndicator
的内容,改个名字,然后稍微修改一下代码。 -
具体做法这篇文章写的非常清楚:Flutter tabbar自定义indicator的固定宽度、圆角
参考文章
Flutter UnderlineTabIndicator BoxDecoration ShapeDecoration FlutterLogoDecoration
网友评论