【发布时间】:2021-12-21 23:09:49
【问题描述】:
我使用Container 的颜色来制作类似指示器,而不是使用TabBar 的指示器,因为我必须对Container 实现一些动画。
当TabController 索引发生变化时,在监听器中调用setState。尝试在TabBar 上滚动/滑动,TabBar 没有正确更改索引,因为listener 不听TabBar 的动画。
我尝试过使用tabcontroller.animation.addListener 方法,但没有任何解决方法可以让我控制滚动移动。
下面的附加视频演示了在TabBar 上应用的点击和滚动/滑动。
代码:
class TabTest extends StatefulWidget {
@override
_TabTestState createState() => _TabTestState();
}
class _TabTestState extends State<TabTest> with TickerProviderStateMixin {
late TabController _tabController;
late List<AnimationController> _animationControllers;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this)
..addListener(_listener);
_animationControllers = List.generate(
4,
(i) => AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 350),
));
}
@override
Widget build(BuildContext context) {
List<IconData> _tabIconData = [
Icons.card_giftcard,
Icons.confirmation_num_outlined,
Icons.emoji_events_outlined,
Icons.wine_bar_outlined,
];
List<String> _tabLabel = [
'Tab1',
'Tab2',
'Tab3',
'Tab4',
];
Widget _tab({
required IconData iconData,
required String label,
required bool isSelectedIndex,
// required double widthAnimation,
// required heightAnimation,
}) {
const _tabTextStyle = TextStyle(
fontWeight: FontWeight.w300, fontSize: 12, color: Colors.black);
return AnimatedContainer(
duration: Duration(milliseconds: 300),
padding: EdgeInsets.only(bottom: 2.0),
height: 55,
width: double.infinity, //_animContainerWidth - widthAnimation,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: isSelectedIndex ? Colors.black : Colors.transparent,
width: 2.0,
),
),
),
child: Tab(
iconMargin: EdgeInsets.only(bottom: 5.0),
icon: Icon(iconData, color: Colors.black),
child: Text(label, style: _tabTextStyle),
),
);
}
List<Widget> _animationGenerator() {
return List.generate(
4,
(index) => ClipRRect(
child: AnimatedBuilder(
animation: _animationControllers[index],
builder: (ctx, _) {
final value = _animationControllers[index].value;
final angle = math.sin(value * math.pi * 2) * math.pi * 0.04;
return Transform.rotate(
angle: angle,
child: _tab(
iconData: _tabIconData[index],
label: _tabLabel[index],
isSelectedIndex: _tabController.index == index,
));
}),
),
);
}
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(100),
child: AppBar(
iconTheme: Theme.of(context).iconTheme,
title: Text(
'Tab Bar',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
centerTitle: true,
bottom: PreferredSize(
preferredSize: Size.fromHeight(20),
child: Container(
child: TabBar(
controller: _tabController,
labelPadding: EdgeInsets.only(top: 5.0, bottom: 2.0),
indicatorColor: Colors.transparent,
tabs: _animationGenerator(),
),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.white,
spreadRadius: 5.0,
offset: Offset(0, 3))
],
),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: List.generate(
4,
(index) => FittedBox(
child: Text('Tab $index'),
)),
),
);
}
void _listener() {
if (_tabController.indexIsChanging) {
setState(() {}); // To refresh color for Container bottom Border
_animationControllers[_tabController.previousIndex].reverse();
} else {
_animationControllers[_tabController.index].forward();
}
}
@override
void dispose() {
super.dispose();
_tabController.removeListener(_listener);
}
}
【问题讨论】:
-
嘿@pskink!再次感谢您的回复!但有时当我滑动/滚动 TabBar 时,它不会像点击时那样为黑线设置动画。不知何故,我认为滚动/幻灯片可以将动画控制器的设置器设置为 0。
-
我不知道我可以为此使用 FractionalTranslation!感谢您再次分享!
-
哦,我明白了,我把 reset 放在了监听器的 else 中。谢谢@pskink!
-
关键是另一个
AnimatedBuilder从_tab方法返回(而不是AnimatedContainer) -
欢迎您,但老实说,我会使用
CustomPaint而不是AnimatedBuilder+FractionalTranslation+SizedBox+ColoredBox- 而不是这 4 个小部件,您可以使用 @987654342 做同样的事情@ - 更快更优雅的解决方案
标签: flutter dart user-interface animation user-experience