Flutter之Widget點擊態背景色

本文主要解決快速按下鬆開後,仍然可以看到背景色的變化。

在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);
  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章