Last active
June 22, 2024 01:26
-
-
Save loic-hamdi/c91ecf08dba3033b954456ea8466d53b to your computer and use it in GitHub Desktop.
Validation Button Timer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math'; | |
import 'package:flutter/material.dart'; | |
void main() => runApp(const MyApp()); | |
class MyApp extends StatefulWidget { | |
const MyApp({super.key}); | |
@override | |
State<MyApp> createState() => _MyAppState(); | |
} | |
class _MyAppState extends State<MyApp> { | |
final data = <ValidationButton>[]; | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: Scaffold( | |
appBar: AppBar(title: const Text('Validation Button Timer')), | |
body: Column( | |
children: [ | |
ListView.builder( | |
shrinkWrap: true, | |
itemCount: data.length, | |
itemBuilder: (BuildContext c, int i) => data[i], | |
), | |
], | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: () => setState(() => data.add(ValidationButton(id: Random().nextInt(5000).toString()))), | |
child: const Icon(Icons.add), | |
), | |
), | |
); | |
} | |
} | |
class ValidationButton extends StatefulWidget { | |
final String? id; | |
final int time; | |
const ValidationButton({super.key, this.time = 20, this.id}); | |
@override | |
ValidationButtonState createState() => ValidationButtonState(); | |
} | |
class ValidationButtonState extends State<ValidationButton> with SingleTickerProviderStateMixin { | |
AnimationController? _controller; | |
Animation<double>? _animation; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = AnimationController( | |
vsync: this, | |
duration: Duration(seconds: widget.time), | |
)..addStatusListener((status) { | |
if (status == AnimationStatus.completed) endAnim(); | |
}); | |
if (context.mounted && _controller != null) _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller!); | |
_startTimer(); | |
} | |
void _startTimer() => _controller?.forward(from: 0.0); | |
void endAnim() { | |
if (context.mounted) { | |
setState(() { | |
_controller?.stop(); | |
_animation = null; | |
}); | |
} | |
} | |
@override | |
void dispose() { | |
_controller?.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
if (_animation == null) return const SizedBox.shrink(); | |
return Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Container( | |
height: 60, | |
width: 200, | |
padding: const EdgeInsets.all(8.0), | |
child: ClipRRect( | |
borderRadius: BorderRadius.circular(4), | |
child: CustomPaint( | |
painter: TimerButtonPainter(animation: _animation!), | |
child: InkWell( | |
onTap: () => endAnim(), | |
child: Stack( | |
alignment: Alignment.center, | |
children: [ | |
const Icon(Icons.done, color: Colors.white), | |
if (widget.id != null) Positioned(top: 12, right: 8.0, child: Text(widget.id!)), | |
], | |
), | |
), | |
), | |
), | |
), | |
], | |
); | |
} | |
} | |
class TimerButtonPainter extends CustomPainter { | |
final Animation<double> animation; | |
TimerButtonPainter({required this.animation}) : super(repaint: animation); | |
@override | |
void paint(Canvas canvas, Size size) { | |
final Paint paint = Paint() | |
..shader = LinearGradient( | |
begin: Alignment.centerLeft, | |
end: Alignment.centerRight, | |
colors: const [Color(0xFF164B35), Color(0xFF1F845A)], | |
stops: [animation.value, animation.value], | |
).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); | |
final Rect rect = Rect.fromLTWH(0, 0, size.width, size.height); | |
final RRect rrect = RRect.fromRectAndRadius(rect, const Radius.circular(4)); | |
canvas.drawRRect(rrect, paint); | |
} | |
@override | |
bool shouldRepaint(CustomPainter oldDelegate) => true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment