TabBar文字抖动:
当为TabBar设置选择和未选择不同大小字体尺寸时滑动Tabbar字体大小动效变化有明显的抖动:
解决方案:
方案1:注释TabBar中文本样式属性,通过监听TabBar的滑动结果,主动刷新改变Tab文本样式。
方案2:修改tabs源码。
方案一:
tab切换过程文本没有缩放效果,比较影响用户体验。
代码实现:
class DemoWidgetTabBar extends StatefulWidget {
_DemoWidgetTabBarState createState() => _DemoWidgetTabBarState();
}
class _DemoWidgetTabBarState extends State<DemoWidgetTabBar> {
int tabIndex = 0; // 当前选中索引
Widget build(BuildContext context) {
return TabBar(
onTap: (index){
// 每当TabBar 切换更新索引
setState(() {
tabIndex = index;
});
},
isScrollable: true, // 是否滚动
unselectedLabelColor: Colors.black54, //未选中颜色
labelColor: Colors.blue, //选中颜色
//注释掉TabBar的文本属性,在Tab中通过Text的TextStyle控制
// labelStyle: TextStyle(fontSize: 20.0),
// unselectedLabelStyle: TextStyle(fontSize: 16.0),
tabs: [
Tab(child: Text('首页1',style: TextStyle(fontSize: tabIndex == 0 ? 20:16),)),
Tab(child: Text('首页2',style: TextStyle(fontSize: tabIndex == 1 ? 20:16),)),
Tab(child: Text('首页3',style: TextStyle(fontSize: tabIndex == 2 ? 20:16),)),
Tab(child: Text('首页4',style: TextStyle(fontSize: tabIndex == 3 ? 20:16),)),
],
);
}
}
方案二:
源码中找到tabs.dart文件。拷贝至项目目录,重命名为demo_tabs.dart。找到并修改_TabStyle的build方法。
从这段代码我们可以看出,tabbar在滑动过程中,会根据滑动动画的进度计算出文字的大小和颜色并绘制,这应该是官方对于中文绘制的不友善导致的文字抖动,目前也没找到很完美的解决方案。临时处理是在child外加一层Transform.scale组件,使文字通过缩放的形式完成滑动过度。代码如下:
class _TabStyle extends AnimatedWidget {
const _TabStyle({
Key key,
Animation<double> animation,
this.selected,
this.labelColor,
this.unselectedLabelColor,
this.labelStyle,
this.unselectedLabelStyle,
this.child,
}) : super(key: key, listenable: animation);
final TextStyle labelStyle;
final TextStyle unselectedLabelStyle;
final bool selected;
final Color labelColor;
final Color unselectedLabelColor;
final Widget child;
Widget build(BuildContext context) {
final ThemeData themeData = Theme.of(context);
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
final Animation<double> animation = listenable as Animation<double>;
// To enable TextStyle.lerp(style1, style2, value), both styles must have
// the same value of inherit. Force that to be inherit=true here.
// final TextStyle defaultStyle = (labelStyle
// ?? tabBarTheme.labelStyle
// ?? themeData.primaryTextTheme.bodyText1
// ).copyWith(inherit: true);
// final TextStyle defaultUnselectedStyle = (unselectedLabelStyle
// ?? tabBarTheme.unselectedLabelStyle
// ?? labelStyle
// ?? themeData.primaryTextTheme.bodyText1
// ).copyWith(inherit: true);
// final TextStyle textStyle = selected
// ? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value)
// : TextStyle.lerp(defaultUnselectedStyle, defaultStyle, animation.value);
final TextStyle defaultUnselectedStyle = (unselectedLabelStyle ??
tabBarTheme.unselectedLabelStyle ??
labelStyle ??
themeData.primaryTextTheme.bodyText1)
.copyWith(inherit: true);
final TextStyle defaultStyle = (labelStyle ??
tabBarTheme.labelStyle ??
themeData.primaryTextTheme.bodyText1)
.copyWith(inherit: true)
.copyWith(fontSize: defaultUnselectedStyle.fontSize);
final TextStyle textStyle = selected
? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value)
: TextStyle.lerp(defaultUnselectedStyle, defaultStyle, animation.value);
final Color selectedColor = labelColor
?? tabBarTheme.labelColor
?? themeData.primaryTextTheme.bodyText1.color;
final Color unselectedColor = unselectedLabelColor
?? tabBarTheme.unselectedLabelColor
?? selectedColor.withAlpha(0xB2); // 70% alpha
final Color color = selected
? Color.lerp(selectedColor, unselectedColor, animation.value)
: Color.lerp(unselectedColor, selectedColor, animation.value);
final double multiple = labelStyle.fontSize / unselectedLabelStyle.fontSize;
final double _scale = selected
? lerpDouble(multiple, 1, animation.value)
: lerpDouble(1, multiple, animation.value);
return DefaultTextStyle(
style: textStyle.copyWith(color: color),
child: IconTheme.merge(
data: IconThemeData(
size: 24.0,
color: color,
),
// 使用缩放代替动画绘制
child: Transform.scale(
scale: _scale,
child: child,
),
),
);
}
}
使用
import '../demo_tabs.dart' as demoTab;
//将原本TabBar()改为demoTab.TabBar()
demoTab.TabBar(),