64 lines
1.4 KiB
Dart
64 lines
1.4 KiB
Dart
import 'dart:math';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class ShakeWidget extends StatefulWidget {
|
|
final Widget child;
|
|
final double shakeOffset;
|
|
final int shakeCount;
|
|
final Duration duration;
|
|
|
|
const ShakeWidget({
|
|
super.key,
|
|
required this.child,
|
|
this.shakeOffset = 10.0,
|
|
this.shakeCount = 3,
|
|
this.duration = const Duration(milliseconds: 400),
|
|
});
|
|
|
|
@override
|
|
ShakeWidgetState createState() => ShakeWidgetState();
|
|
}
|
|
|
|
class ShakeWidgetState extends State<ShakeWidget>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(vsync: this, duration: widget.duration);
|
|
_controller.addStatusListener((status) {
|
|
if (status == AnimationStatus.completed) {
|
|
_controller.reset();
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void shake() {
|
|
_controller.forward();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _controller,
|
|
builder: (context, child) {
|
|
final double sineValue = sin(
|
|
widget.shakeCount * 2 * pi * _controller.value,
|
|
);
|
|
return Transform.translate(
|
|
offset: Offset(sineValue * widget.shakeOffset, 0),
|
|
child: child,
|
|
);
|
|
},
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|