Free copy-paste Button 008 for Flutter: a ready-to-use button widget with full Dart source code and a live preview. Works on desktop. No external packages.
Copy the Dart code below into a new file in your Flutter project (for example lib/widgets/button_008.dart) and use the widget anywhere in your widget tree.
import 'package:flutter/material.dart';
class Button008 extends StatefulWidget {
const Button008({
super.key,
this.label = 'BUTTON',
this.onTap,
this.color = const Color(0xFF333333),
this.textColor = Colors.white,
this.fontSize = 18.0,
this.padding = const EdgeInsets.symmetric(horizontal: 28, vertical: 15),
});
final String label;
final VoidCallback? onTap;
final Color color, textColor;
final double fontSize;
final EdgeInsetsGeometry padding;
@override
State<Button008> createState() => _Button008State();
}
class _Button008State extends State<Button008>
with SingleTickerProviderStateMixin {
late final AnimationController _shake;
late final Animation<double> _rot;
bool _hovered = false, _pressed = false;
@override
void initState() {
super.initState();
_shake = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
_rot = _shake.drive(
TweenSequence<double>([
TweenSequenceItem(
tween: Tween(
begin: 0.0,
end: 0.122,
).chain(CurveTween(curve: Curves.easeInOut)),
weight: 1,
),
TweenSequenceItem(
tween: Tween(
begin: 0.122,
end: -0.122,
).chain(CurveTween(curve: Curves.easeInOut)),
weight: 1,
),
TweenSequenceItem(
tween: Tween(
begin: -0.122,
end: 0.017,
).chain(CurveTween(curve: Curves.easeInOut)),
weight: 1,
),
TweenSequenceItem(
tween: Tween(
begin: 0.017,
end: 0.0,
).chain(CurveTween(curve: Curves.easeInOut)),
weight: 1,
),
]),
);
}
@override
void dispose() {
_shake.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) {
setState(() => _hovered = true);
_shake.forward(from: 0.0);
},
onExit: (_) => setState(() => _hovered = false),
child: GestureDetector(
onTapDown: (_) => setState(() => _pressed = true),
onTapUp: (_) {
setState(() => _pressed = false);
widget.onTap?.call();
},
onTapCancel: () => setState(() => _pressed = false),
child: AnimatedScale(
scale: _pressed ? 0.96 : 1.0,
duration: const Duration(milliseconds: 500),
child: AnimatedBuilder(
animation: _rot,
builder: (context, child) =>
Transform.rotate(angle: _rot.value, child: child),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Stack(
alignment: Alignment.center,
children: [
Container(
color: widget.color,
padding: widget.padding,
child: Text(
widget.label.toUpperCase(),
style: TextStyle(
color: widget.textColor,
fontSize: widget.fontSize,
fontWeight: FontWeight.w300,
letterSpacing: 0.5,
),
),
),
Positioned(
right: -50,
bottom: -5,
child: AnimatedOpacity(
opacity: _hovered ? 0.15 : 0.0,
duration: const Duration(milliseconds: 1000),
curve: const Cubic(0.02, 0.01, 0.47, 1.0),
child: AnimatedScale(
scale: _hovered ? 1.1 : 0.6,
duration: const Duration(milliseconds: 200),
curve: const Cubic(0.02, 0.01, 0.47, 1.0),
child: Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
),
),
),
],
),
),
),
),
),
);
}
}