Blame view

lib/common/widgets/option_widget.dart 3.68 KB
61e3478a   吴启风   feat:封装具备答错摇晃、答对缩...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  import 'package:flutter/material.dart';
  import 'package:wow_english/common/widgets/throttledGesture_gesture_detector.dart';
  
  import '../../utils/log_util.dart';
  
  /// 选择题选项组件,具备答错摇晃、答对缩放动效能力
  class OptionWidget extends StatefulWidget {
    final Widget child;
  
    //正确缩放动画;错误摇晃动画;为空即非选中选项,无操作
    final bool? isCorrect;
    final bool isClickable;
    final VoidCallback? onTap;
  
    const OptionWidget({
      Key? key,
      required this.child,
      this.isCorrect,
      this.isClickable = true,
      this.onTap,
    }) : super(key: key);
  
    @override
    _OptionWidgetState createState() => _OptionWidgetState();
  }
  
  class _OptionWidgetState extends State<OptionWidget>
      with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    late Animation<double> _shakeAnimation;
    late Animation<double> _scaleAnimation;
    static const String TAG = 'OptionWidget';
  
    @override
    void initState() {
      super.initState();
  
      _controller = AnimationController(
        vsync: this,
        duration: const Duration(milliseconds: 500),
      );
  
      _shakeAnimation = TweenSequence([
        TweenSequenceItem(
          tween: Tween(begin: 0.0, end: 10.0)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 1,
        ),
        TweenSequenceItem(
          tween: Tween(begin: 10.0, end: -10.0)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 1,
        ),
        TweenSequenceItem(
          tween: Tween(begin: -10.0, end: 10.0)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 1,
        ),
        TweenSequenceItem(
          tween: Tween(begin: 10.0, end: -10.0)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 1,
        ),
        TweenSequenceItem(
          tween: Tween(begin: -10.0, end: 0.0)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 1,
        ),
      ]).animate(_controller);
  
      _scaleAnimation = TweenSequence<double>([
        TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.8), weight: 1),
        TweenSequenceItem(tween: Tween(begin: 0.8, end: 1.25), weight: 1),
        TweenSequenceItem(tween: Tween(begin: 1.25, end: 1.0), weight: 1),
      ]).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeInOut,
      ));
    }
  
    @override
    void didUpdateWidget(OptionWidget oldWidget) {
      super.didUpdateWidget(oldWidget);
      Log.d(
e0e89ade   吴启风   feat:选择选项组件动画防抖
85
86
87
88
89
90
91
92
93
          '$TAG ${identityHashCode(this)} didUpdateWidget widget.isCorrect=${widget.isCorrect} oldWidget.isCorrect=${oldWidget.isCorrect} isAnimation=${_controller.isAnimating} status=${_controller.status}');
      if (widget.isCorrect == oldWidget.isCorrect && _controller.isAnimating) {
        return;
      }
      _controller.reset();
      if (widget.isCorrect == true) {
        _controller.forward();
      } else if (widget.isCorrect == false) {
        _controller.forward();
61e3478a   吴启风   feat:封装具备答错摇晃、答对缩...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
      }
    }
  
    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          double offsetX = widget.isCorrect == false ? _shakeAnimation.value : 0;
          double scale = widget.isCorrect == true ? _scaleAnimation.value : 1.0;
  
          return ThrottledGestureDetector(
            onTap: widget.isClickable ? widget.onTap : null,
            child: Transform.translate(
              offset: Offset(offsetX, 0),
              child: Transform.scale(
                scale: scale,
                child: Opacity(
                  opacity: widget.isClickable ? 1.0 : 0.5,
                  child: widget.child,
                ),
              ),
            ),
          );
        },
      );
    }
  }