|
class FineButton extends StatefulWidget { |
|
const FineButton({super.key, this.onTap, this.label = 'label'}); |
|
|
|
final VoidCallback? onTap; |
|
final String label; |
|
|
|
@override |
|
State<FineButton> createState() => _FineButtonState(); |
|
} |
|
|
|
class _FineButtonState extends State<FineButton> |
|
with SingleTickerProviderStateMixin { |
|
static const _buttonShape = RoundedRectangleBorder( |
|
borderRadius: BorderRadius.all(Radius.circular(32))); |
|
static const _distance = 5.0; |
|
static const _size = 48.0; |
|
|
|
static final _progress = Tween<double>(begin: _distance, end: 0); |
|
|
|
late final AnimationController controller; |
|
late final Animation<double> _progressAnim; |
|
|
|
@override |
|
void initState() { |
|
super.initState(); |
|
controller = AnimationController( |
|
vsync: this, duration: const Duration(milliseconds: 700)); |
|
|
|
_progressAnim = _progress |
|
.animate(CurvedAnimation(parent: controller, curve: Curves.ease)); |
|
} |
|
|
|
@override |
|
void dispose() { |
|
controller.dispose(); |
|
super.dispose(); |
|
} |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return SizedBox( |
|
height: _size, |
|
width: double.infinity, |
|
child: AnimatedBuilder( |
|
animation: controller, |
|
builder: (context, child) { |
|
return Stack( |
|
children: [ |
|
Positioned.fill( |
|
left: _distance, |
|
bottom: _distance, |
|
child: Container( |
|
height: 43, |
|
width: double.infinity, |
|
decoration: ShapeDecoration( |
|
shape: _buttonShape, |
|
color: Colors.green.shade300, |
|
), |
|
), |
|
), |
|
Positioned.fill( |
|
top: _progressAnim.value, |
|
right: _progressAnim.value, |
|
bottom: 5 - _progressAnim.value, |
|
left: 5 - _progressAnim.value, |
|
child: Container( |
|
width: double.infinity, |
|
height: 43, |
|
alignment: Alignment.center, |
|
decoration: ShapeDecoration( |
|
shape: _buttonShape, |
|
color: Theme.of(context).colorScheme.primaryContainer, |
|
), |
|
child: Text( |
|
widget.label, |
|
style: Theme.of(context).textTheme.titleMedium?.copyWith( |
|
color: Colors.white, |
|
), |
|
), |
|
), |
|
), |
|
Positioned.fill( |
|
top: 3, |
|
right: 3, |
|
child: InkWell( |
|
onTap: widget.onTap, |
|
onTapUp: (details) { |
|
controller.reverse(); |
|
}, |
|
onTapDown: (details) { |
|
controller.forward(); |
|
}, |
|
customBorder: _buttonShape, |
|
splashColor: Colors.green.shade500, |
|
), |
|
), |
|
], |
|
); |
|
}, |
|
), |
|
); |
|
} |
|
} |