本文主要解決快速按下鬆開後,仍然可以看到背景色的變化。
在flutter中有個AnimatedContainer,其可以實現按下時背景色變化,鬆開後背景色還原。但是快速按下鬆開後,其背景色無變化。原因是,背景色變化需要一個過程,而快速按下鬆開後就立即結束動畫響應事件了。
自定義實現代碼如下:
class StateButton extends StatefulWidget {
final double width;
final double height;
final double radius;
final Color normal;
final Color press;
final Widget fore;
final VoidCallback onPressed;
StateButton(
{Key key,
this.width,
this.height,
this.radius,
this.normal,
this.press,
this.fore,
this.onPressed})
: super(key: key);
@override
State<StatefulWidget> createState() => _StateButton(normal, press);
}
enum _State { None, Down, Up, Cancel }
class _StateButton extends State<StateButton>
with SingleTickerProviderStateMixin {
var _state = _State.None;
AnimationController _controller;
Animation<Color> _animation;
_StateButton(Color normal, Color press) {
_controller =
AnimationController(duration: Duration(milliseconds: 150), vsync: this);
_animation = ColorTween(begin: normal, end: press)
.animate(_controller);
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 按下動畫結束時,若已鬆開,則動畫還原
if (_state == _State.Up) {
_controller.reverse();
}
} else if (status == AnimationStatus.dismissed) {
// 動畫還原結束時,若非取消事件,則觸發外部事件
bool action = true;
if (_state == _State.Cancel) {
action = false;
}
_state = _State.None;
if (action && widget.onPressed != null) widget.onPressed();
}
});
_controller.addListener(() {
setState(() {});
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
void _onMouseDown() {
if (_state != _State.None) return;
_state = _State.Down;
_controller.forward();
}
void _onMouseUp() {
if (_state != _State.Down) return;
_state = _State.Up;
if (_controller.isAnimating) return;
_controller.reverse();
}
void _onMouseCancel() {
if (_state != _State.Down) return;
_state = _State.Cancel;
_controller.reverse();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (t) {
_onMouseDown();
},
onTapUp: (t) {
_onMouseUp();
},
onTapCancel: () {
_onMouseCancel();
},
child: Container(
width: widget.width,
height: widget.height,
alignment: Alignment.center,
decoration: BoxDecoration(
color: _animation.value,
borderRadius: BorderRadius.circular(widget.radius)),
child: widget.fore));
}
}
// 封裝成函數,調用更方便
static Widget colorButton(Widget text,
{double width = double.infinity,
double height = 44,
double borderRadius = 22,
Color normal = const Color(0xfffc1e1e),
Color press = const Color(0xffff4f42),
VoidCallback onPressed}) {
return StateButton(
width: width,
height: height,
radius: borderRadius,
normal: normal,
press: press,
fore: text,
onPressed: onPressed);
}