import 'package:flutter/material.dart'; import '../../../utils/log_util.dart'; ///左右晃动组件,用于答错场景 class ShakeWidget extends StatefulWidget { final Widget child; final int shakeCount; final double shakeOffset; final Duration duration; final bool shouldShake; const ShakeWidget({ Key? key, required this.child, this.shakeCount = 2, this.shakeOffset = 10.0, this.duration = const Duration(milliseconds: 500), this.shouldShake = false, }) : super(key: key); @override _ShakeWidgetState createState() => _ShakeWidgetState(); } class _ShakeWidgetState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; static const String TAG = "ShakeWidget"; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: widget.duration, ); _animation = TweenSequence([ TweenSequenceItem( tween: Tween(begin: 0.0, end: widget.shakeOffset) .chain(CurveTween(curve: Curves.easeInOut)), weight: 1, ), TweenSequenceItem( tween: Tween(begin: widget.shakeOffset, end: -widget.shakeOffset) .chain(CurveTween(curve: Curves.easeInOut)), weight: 1, ), TweenSequenceItem( tween: Tween(begin: -widget.shakeOffset, end: widget.shakeOffset) .chain(CurveTween(curve: Curves.easeInOut)), weight: 1, ), TweenSequenceItem( tween: Tween(begin: widget.shakeOffset, end: -widget.shakeOffset) .chain(CurveTween(curve: Curves.easeInOut)), weight: 1, ), TweenSequenceItem( tween: Tween(begin: -widget.shakeOffset, end: 0.0) .chain(CurveTween(curve: Curves.easeInOut)), weight: 1, ), ]).animate(_controller); } @override void didUpdateWidget(covariant ShakeWidget oldWidget) { super.didUpdateWidget(oldWidget); Log.d("$TAG didUpdateWidget widget.shouldShake=${widget.shouldShake} oldWidget.shouldShake=${oldWidget.shouldShake} isAnimating=${_controller.isAnimating}"); // if (widget.shouldShake && !oldWidget.shouldShake) { if (widget.shouldShake && !_controller.isAnimating) { _controller.forward(from: 0.0); } else if (!widget.shouldShake && _controller.isAnimating) { _controller.stop(); } } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(_animation.value, 0), child: widget.child, ); }, child: widget.child, ); } }