Flutter TabBar切换文字抖动动画解决方案(替换动画)

使用Flutter自带的TabBar切换动画文字会有抖动问题,也可以修改源码,我觉得没必要。
我们可以不使用这两个参数,自己通过部件的刷新来实现切换文字变大的效果就可以解决抖动问题。
主要是利用了AnimatedDefaultTextStyle。

⚠️
1、替换tab自实现text改变动画后,此时滑动切换tabView上面tabbar不会联动,可以用TabController监听实现

2、TabController监听是在滑动结束后才执行的,会有一个延迟效果,如果效果不满意可以用NotificationListener包一层监听滑动过程实现迅速动画

3、再进一步,我看有的根据滑动距离实时更改文字大小,更麻烦一点,但我觉得真没必要,我的项目就做到第二步,效果设计就觉得可以了

    AnimatedScale(
      scale: 1 + progress * 0.3,
      duration: const Duration(milliseconds: 100),
      child: Text(tabName),
    ),

demo:

import 'package:flutter/material.dart';

class HomePage4 extends StatefulWidget {
  @override
  _HomePage4State createState() => _HomePage4State();
}

class _HomePage4State extends State<HomePage4> with TickerProviderStateMixin {
  final List<String> _tabs = ['哈哈哈1', '哈哈哈2', '哈哈哈3', '哈哈哈4', '哈哈哈5', '哈哈哈6'];
  late TabController _controller;
  int _currentIndex = 0;

  @override
  void initState() {
    super.initState();
    _controller = TabController(length: _tabs.length, vsync: this);
    // _controller.addListener(() {
    //   if (_controller.index == _controller.animation?.value) {
    //     setState(() {
    //       _currentIndex = _controller.index;
    //     });
    //   }
    // });
  }

  ///build
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Container(
            height: 100,
            color: Colors.blue,
          ),
          SizedBox(
            height: 60,
            child: TabBar(
              isScrollable: true,
              labelPadding: const EdgeInsets.only(left: 8, right: 8),
              indicator: const BoxDecoration(),
              overlayColor: MaterialStateProperty.all(Colors.transparent),
              controller: _controller,
              // 不使用自带改变效果
              // labelColor: Colors.black,
              // labelStyle: const TextStyle(fontSize: 25),
              // unselectedLabelColor: Colors.black45,
              // unselectedLabelStyle: const TextStyle(fontSize: 15),
              // tabs: _tabs!.map((e) => Text(e)).toList(),
              tabs: _tabs.asMap().entries.map((e) {
                return _animatedTab(e.key, e.value);
              }).toList(),
              // onTap: (index) {
              //   setState(() {
              //     _currentIndex = index;
              //   });
              // },
            ),
          ),
          Expanded(
            child: NotificationListener(
              onNotification: (ScrollNotification scrollNotification) {
                // 监听实时更新,迅速动画,TabController监听有效的是ScrollEndNotification
                if (scrollNotification is ScrollUpdateNotification) {
                  // 一般页面都是左右滚动
                  if (scrollNotification.metrics.axisDirection == AxisDirection.right) {
                    // 滚动百分比,0.0-1.0
                    double progress = scrollNotification.metrics.pixels / scrollNotification.metrics.maxScrollExtent;
                    double unit = 1.0 / _tabs.length;
                    int index = progress ~/ unit;
                    if (index != _currentIndex && index < _tabs.length) {
                      setState(() {
                        _currentIndex = index;
                        print('tabbar选中:$_currentIndex');
                      });
                    }
                  }
                }
                return true;
              },
              child: TabBarView(
                controller: _controller,
                children: _tabs.asMap().entries.map((e) {
                  return _content(e.key, e.value);
                }).toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _animatedTab(int index, String text) {
    TextStyle normalStyle = const TextStyle(
      color: Colors.black45,
      fontSize: 15,
    );
    TextStyle selectedStyle = const TextStyle(
      color: Colors.black,
      fontSize: 25,
    );
    return Tab(
      child: AnimatedDefaultTextStyle(
        style: _currentIndex == index ? selectedStyle : normalStyle,
        duration: const Duration(milliseconds: 100),
        child: Text(text),
      ),
    );
  }

  Widget _content(int index, String text) {
    return Container(
      color: Colors.lightBlueAccent,
      alignment: Alignment.center,
      child: Text('$index-$text'),
    );
  }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。