【flutter】tabbar文字抖动处理方案

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(),

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值