在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);
}