在flutter中TabBar + TabBarView可以实现类似Android中的indicator + viewpage的效果.
一.TabBar参数
参数 | 说明 |
---|---|
unselectedLabelColor | 未选中时标签的颜色 |
labelColor | 选中时标签的颜色 |
indicatorColor | 指示器颜色 |
indicatorWeight | 指示器高度 |
indicatorSize | 指示器宽度, 值为tab或lable |
indicator | 指示器的形状, 类型为Decoration |
一般可以为indicator
设置UnderlineTabIndicator
对象. 而indicatorColor
和indicatorWeight
内部其实也是构建了 UnderlineTabIndicator
.
具体源码为:(tabs.dart/_TabBarState)
Decoration get _indicator {
if (widget.indicator != null)
return widget.indicator;
final ThemeData themeData = Theme.of(context);
if (themeData.tabBarTheme.indicator != null)
return themeData.tabBarTheme.indicator;
Color color = widget.indicatorColor ?? themeData.indicatorColor;
if (color.value == Material.of(context).color.value)
color = Colors.white;
return UnderlineTabIndicator(
insets: widget.indicatorPadding,
borderSide: BorderSide(
width: widget.indicatorWeight,
color: color,
),
);
}
而indicatorSize
则传递给了_IndicatorPainter
. 其根据tab
orlabel
计算绘制区域大小.
Rect indicatorRect(Size tabBarSize, int tabIndex) {
assert(_currentTabOffsets != null);
assert(_currentTextDirection != null);
assert(_currentTabOffsets.isNotEmpty);
assert(tabIndex >= 0);
assert(tabIndex <= maxTabIndex);
double tabLeft, tabRight;
switch (_currentTextDirection) {
case TextDirection.rtl:
tabLeft = _currentTabOffsets[tabIndex + 1];
tabRight = _currentTabOffsets[tabIndex];
break;
case TextDirection.ltr:
tabLeft = _currentTabOffsets[tabIndex];
tabRight = _currentTabOffsets[tabIndex + 1];
break;
}
if (indicatorSize == TabBarIndicatorSize.label) {
final double tabWidth = tabKeys[tabIndex].currentContext.size.width;
final double delta = ((tabRight - tabLeft) - tabWidth) / 2.0;
tabLeft += delta;
tabRight -= delta;
}
return Rect.fromLTWH(tabLeft, 0.0, tabRight - tabLeft, tabBarSize.height);
}
二. 自定义indicator
比如我们想支持指定宽度, 上面的那些参数无法达成, 那就需要重写一个自定义Decoration. 直接copyUnderlineTabIndicator
代码
Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
assert(rect != null);
assert(textDirection != null);
final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
return Rect.fromLTWH(
indicator.left,
indicator.bottom - borderSide.width,
indicator.width,
borderSide.width,
);
}
修改为
Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
assert(rect != null);
assert(textDirection != null);
final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
//希望的宽度
double wantWidth = 20;
//取中间坐标
double cw = (indicator.left + indicator.right) / 2;
return Rect.fromLTWH(cw - wantWidth / 2,
indicator.bottom - borderSide.width, wantWidth, borderSide.width);
}