试试这个解决方案。我觉得这几乎是你所需要的。您只需添加 SizeTransition 小部件。
询问您是否有任何问题。
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
int _pressedButton;
Animation<double> _animation;
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_animation = Tween<double>(begin: 1.0, end: 0.0)
.animate(_controller)
..addListener(() {
setState(() { });
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test"),
),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
_animatedButton(1),
_animatedButton(2),
_animatedButton(3),
_animatedButton(4)
]
),
Text(_pressedButton != null ? "$_pressedButton button pressed" : "No button pressed"),
RaisedButton(
child: Text("Reset"),
onPressed: () {
_controller.reset();
}
)
]
)
);
}
Widget _animatedButton(int button) {
if (button != _pressedButton) {
return SizeTransition(
sizeFactor: _animation,
axis: Axis.horizontal,
child: Opacity(
opacity: _animation.value,
child: _button(button)
)
);
} else {
return _button(button);
}
}
Widget _button(int button) {
return RaisedButton(
onPressed: () => onButtonClick(button),
child: Text("Button $button")
);
}
void onButtonClick(int button) {
setState(() {
_pressedButton = button;
});
_controller.forward();
}
}
更新 1
检查另一种方法来做你需要的。下面的代码中几乎没有不同的东西。
- 将 SingleTickerProviderStateMixin 更改为 TickerProviderStateMixin。
- 使用两个动画控制器和动画(用于淡出未选中的按钮和向左滑动选中的按钮)。
- 按顺序运行动画(请参阅动画补间监听器)。
- 添加 bool _buttonSelected 以跟踪动画的完成情况。
- 使用 _buttonSelected 构建正确的小部件(小部件 _buttonsWidget())
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
int _pressedButton = -1;
bool _buttonSelected = false;
Animation<double> _animationFadeOut;
AnimationController _controllerFadeOut;
Animation<double> _animationSlideLeft;
AnimationController _controllerSlideLeft;
@override
void initState() {
super.initState();
_initFadeOutAnimation();
_initSlideLeftAnimation();
}
void _initFadeOutAnimation() {
_controllerFadeOut = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_animationFadeOut = Tween<double>(begin: 1.0, end: 0.0)
.animate(_controllerFadeOut)
..addListener(() {
setState(() {
if (_controllerFadeOut.isCompleted && !_controllerSlideLeft.isAnimating) {
_controllerSlideLeft.forward();
}
});
});
}
void _initSlideLeftAnimation() {
_controllerSlideLeft = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_animationSlideLeft = Tween<double>(begin: 1.0, end: 0.0)
.animate(_controllerSlideLeft)
..addListener(() {
setState(() {
if (_controllerSlideLeft.isCompleted) {
_buttonSelected = true;
}
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test"),
),
body: Column(
children: <Widget>[
_buttonsWidget(),
Text(_pressedButton != null ? "$_pressedButton button pressed" : "No button pressed"),
RaisedButton(
child: Text("Reset"),
onPressed: () {
_controllerFadeOut.reset();
_controllerSlideLeft.reset();
_pressedButton = -1;
_buttonSelected = false;
}
)
]
)
);
}
Widget _buttonsWidget() {
if (_buttonSelected) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[_buttonWidget(_pressedButton)]
);
} else {
return Row(
children: <Widget>[
_animatedButtonWidget(1),
_animatedButtonWidget(2),
_animatedButtonWidget(3),
_animatedButtonWidget(4)
]
);
}
}
Widget _animatedButtonWidget(int button) {
if (button == _pressedButton) {
return _buttonWidget(button);
} else {
return SizeTransition(
sizeFactor: _animationSlideLeft,
axis: Axis.horizontal,
child: Opacity(
opacity: _animationFadeOut.value,
child: _buttonWidget(button)
)
);
}
}
Widget _buttonWidget(int button) {
return RaisedButton(
onPressed: () => _onButtonClick(button),
child: Text("Button $button")
);
}
void _onButtonClick(int button) {
setState(() {
_pressedButton = button;
});
_controllerFadeOut.forward();
}
}