本文最后更新于 93 天前,其中的信息可能已经有所发展或是发生改变。
- AnimatedSwitcher>
- controller.drive(Tween(begin:xxx,end:xxx))
- Tween(begin:xxx,end:xxx).chain(CurveTween(curve: Curves.elasticInOut)).animate(controller)
- CurveTween(curve: Inteval(0.5,1.0)) 动画区间(表示从后半段才开始动画)
import 'package:flutter/material.dart';
// 核心:TweenSequenceItem、Transform、Matrix、类接口回调
class ShakeAnimatedWidget extends StatefulWidget {
double shake;
Widget child;
Alignment alignment;
ShakeAnimatedController? controller;
// 动画执行次数 0 则无限循环 默认 1次
int loopCount;
Duration? duration;
//摆动幅度
double amplitude;
ShakeAnimatedWidget({
Key? key,
double shake = 1.0,
required Widget child,
Alignment alignment = Alignment.center,
ShakeAnimatedController? controller,
int loopCount = 1,
Duration? duration,
double amplitude = 15,
}): this.shake = shake,
this.child = child,
this.controller = controller,
this.alignment = alignment,
this.duration = duration,
this.loopCount = loopCount,
this.amplitude = amplitude,
super(key: key);
@override
ShakeAnimatedWidgetState createState() => new ShakeAnimatedWidgetState();
}
class ShakeAnimatedWidgetState extends State<ShakeAnimatedWidget> with SingleTickerProviderStateMixin {
AnimationController? _controller;
Animation<double>? _animation;
@override
Widget build(BuildContext context) {
assert(_animation!=null);
return AnimatedBuilder(
animation: _animation!,
builder: (BuildContext context, Widget? child) {
return Transform(
transform: Matrix4.translationValues(_animation!.value * widget.amplitude, 0, 0),
alignment: widget.alignment,
child: widget.child
);
},
);
}
// 用于记录 动画执行次数
int nowExeAnimatedNum = 1;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: widget.duration??Duration(milliseconds: 300),vsync: this);
_animation = TweenSequence<double>([
///TweenSequenceItem来组合其他的Tween
TweenSequenceItem<double>(
tween: Tween(begin: 0, end: widget.shake), weight: 1),
TweenSequenceItem<double>(
tween: Tween(begin: widget.shake, end: 0), weight: 1),
TweenSequenceItem<double>(
tween: Tween(begin: 0, end: -widget.shake), weight: 1),
TweenSequenceItem<double>(
tween: Tween(begin: -widget.shake, end: 0), weight: 1),
TweenSequenceItem<double>(
tween: Tween(begin: 0, end: widget.shake), weight: 1),
TweenSequenceItem<double>(
tween: Tween(begin: widget.shake, end: 0), weight: 1),
]).chain(CurveTween(curve: Curves.linear)).animate(_controller!);
_controller?.addStatusListener(handlerStatus);
widget.controller?.addShakeAnimatedListener(handleListener);
}
@override
void dispose() {
super.dispose();
_controller?.dispose();
_controller = null;
_animation = null;
widget.controller?.removeShakeAnimatedListener();
}
handlerStatus(status) {
// 动画执行 一个循环 否则 不用处理 下面的 状态
if(status == AnimationStatus.completed){
if(widget.loopCount == 0){
_controller?.forward();
}else{
if(nowExeAnimatedNum < widget.loopCount){
_controller?.forward();
nowExeAnimatedNum ++;
}else{
widget.controller?.isAnimating = false;
}
}
}
// else if(status == AnimationStatus.dismissed){ /// 动画结束 停留在 开始位置
//
// }
}
void handleListener(bool start) {
nowExeAnimatedNum = 1;
if(start){
_controller?.reset();
_controller?.forward();
}else{
_controller?.stop();
}
}
}
// 当然可以直接将 AnimatedController传过来 但是限制就比较大 只能调用 Controller一些方法 还有监听啥的。所以吧这些工作全部 到源类 Function 作为桥梁 ye
// 类似接口回调 有点意思啊
typedef ShakeAnimatedListener = void Function(bool start);
class ShakeAnimatedController{
ShakeAnimatedListener? listener;
bool isAnimating = false;
addShakeAnimatedListener(ShakeAnimatedListener listener){
this.listener = listener;
}
void forward(){
if(listener!=null){
isAnimating = true;
listener!(true);
}
}
void stop(){
if(listener!=null){
isAnimating = false;
listener!(false);
}
}
void removeShakeAnimatedListener(){
listener = null;
}
}