Skip to content

Commit fe9600e

Browse files
create FloatingAnimatedButton
1 parent ca82ad5 commit fe9600e

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import 'dart:math';
2+
3+
import 'package:flutter/material.dart';
4+
5+
class FloatingAnimatedButton extends StatefulWidget {
6+
final Widget child;
7+
final Duration stepDuration;
8+
9+
const FloatingAnimatedButton({
10+
super.key,
11+
required this.child,
12+
this.stepDuration = const Duration(seconds: 3),
13+
});
14+
15+
@override
16+
State<FloatingAnimatedButton> createState() => _FloatingAnimatedButtonState();
17+
}
18+
19+
class _FloatingAnimatedButtonState extends State<FloatingAnimatedButton> with SingleTickerProviderStateMixin {
20+
late AnimationController _controller;
21+
late Animation<double> _scale;
22+
late Animation<Offset> _offset;
23+
24+
final Random _random = Random();
25+
double _currentScale = 1.0;
26+
Offset _currentOffset = Offset.zero;
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
32+
_controller = AnimationController(vsync: this);
33+
34+
_setNewRandomAnimation();
35+
36+
// when one random animation finishes → schedule the next one
37+
_controller.addStatusListener((status) {
38+
if (status == AnimationStatus.completed) {
39+
_currentScale = _scale.value;
40+
_currentOffset = _offset.value;
41+
_setNewRandomAnimation();
42+
}
43+
});
44+
}
45+
46+
void _setNewRandomAnimation() {
47+
// generate new random target scale and offset
48+
final newScale = 0.95 + _random.nextDouble() * 0.1;
49+
final newOffset = Offset(
50+
(_random.nextDouble() * 40 - 35) / 100,
51+
(_random.nextDouble() * 40 - 35) / 100,
52+
);
53+
54+
_scale = Tween<double>(
55+
begin: _currentScale,
56+
end: newScale,
57+
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
58+
59+
_offset = Tween<Offset>(
60+
begin: _currentOffset,
61+
end: newOffset,
62+
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
63+
64+
_controller.duration = widget.stepDuration + Duration(milliseconds: _random.nextInt(2000));
65+
66+
_controller.reset();
67+
_controller.forward();
68+
}
69+
70+
@override
71+
void dispose() {
72+
_controller.dispose();
73+
super.dispose();
74+
}
75+
76+
@override
77+
Widget build(BuildContext context) {
78+
return AnimatedBuilder(
79+
animation: _controller,
80+
builder: (_, __) {
81+
return Transform.translate(
82+
offset: _offset.value * 25,
83+
child: Transform.scale(
84+
scale: _scale.value,
85+
child: widget.child,
86+
),
87+
);
88+
},
89+
);
90+
}
91+
}

0 commit comments

Comments
 (0)