From 76d6f90d695043e16bc5692250c6930fc97e45d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bel?= Date: Fri, 6 Aug 2021 15:39:56 +0200 Subject: [PATCH 1/2] Delay attribute (#17) and added more examples --- example/lib/main.dart | 212 +++++++++++++++++++++++++++++++--- lib/shimmer_animation.dart | 37 +++--- lib/src/shimmer_animator.dart | 24 ++-- 3 files changed, 233 insertions(+), 40 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 4ea45a1..a6ee8e0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -17,25 +17,207 @@ class FullPageShimmerExample extends StatelessWidget { class ShimmerPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - body: Shimmer( - // This is the ONLY required parameter - child: Container( - color: Colors.deepPurple, + return SafeArea( + child: Scaffold( + body: Center( + child: SingleChildScrollView( + child: Column(children: [ + Shimmer( + // This is the ONLY required parameter + child: Container( + color: Colors.deepPurple, + height: 200, + width: 200, + ), + // This is the default value + duration: Duration(seconds: 3), + // This is NOT the default value. Default value: Duration(seconds: 0) + interval: Duration(seconds: 5), + // This is the default value + color: Colors.white, + // This is the default value + colorOpacity: 0.3, + // This is the default value + enabled: true, + // This is the default value + direction: ShimmerDirection.fromLTRB(), + ), + SizedBox( + height: 20, + ), + _delayExample(), + SizedBox( + height: 20, + ), + _clipperExample(), + ]), + )), + )); + } + + Widget _delayExample() { + return Column(children: [ + Text("Using delay"), + Shimmer( + child: ElevatedButton( + child: Text("1 sec delay"), + onPressed: () {}, ), - // This is the default value duration: Duration(seconds: 3), - // This is NOT the default value. Default value: Duration(seconds: 0) interval: Duration(seconds: 5), - // This is the default value - color: Colors.white, - // This is the default value - colorOpacity: 0.3, - // This is the default value - enabled: true, - // This is the default value direction: ShimmerDirection.fromLTRB(), + delay: Duration(seconds: 1), ), - ); + Shimmer( + child: ElevatedButton( + child: Text("2 sec delay"), + onPressed: () {}, + ), + duration: Duration(seconds: 3), + interval: Duration(seconds: 5), + direction: ShimmerDirection.fromLTRB(), + delay: Duration(seconds: 2), + ), + ]); + } + + Widget _clipperExample() { + return Row(children: [ + Expanded( + child: Column(children: [ + Text("Without Clippers"), + Padding( + child: Shimmer( + child: ElevatedButton( + child: Text("Rounded Rectangle"), + onPressed: () {}, + style: ElevatedButton.styleFrom( + // if you don't set [tapTargetSize] to shrinkWrap there will be extra margins + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32))), + ), + color: Colors.red, + interval: Duration(milliseconds: 200), + ), + padding: EdgeInsets.symmetric(vertical: 10), + ), + Padding( + child: Shimmer( + child: Container( + child: Center(child: Text("Circle")), + width: 60, + height: 60, + decoration: + BoxDecoration(color: Colors.green, shape: BoxShape.circle), + ), + color: Colors.red, + interval: Duration(milliseconds: 200), + ), + padding: EdgeInsets.symmetric(vertical: 10), + ), + Shimmer( + child: Container( + child: CustomPaint( + painter: CustomShapePainter(), + ), + width: 100, + height: 100), + color: Colors.yellow, + interval: Duration(milliseconds: 200), + ) + ])), + Expanded( + child: Column(children: [ + Text("With Clippers"), + Padding( + child: ClipRRect( + child: Shimmer( + child: ElevatedButton( + child: Text("Rounded Rectangle"), + onPressed: () {}, + style: ElevatedButton.styleFrom( + // if you don't set [tapTargetSize] to shrinkWrap there will be extra margins + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32))), + ), + color: Colors.red, + interval: Duration(milliseconds: 200), + ), + borderRadius: BorderRadius.circular(32), + ), + padding: EdgeInsets.symmetric(vertical: 10), + ), + Padding( + child: ClipOval( + child: Shimmer( + child: Container( + child: Center(child: Text("Circle")), + width: 60, + height: 60, + decoration: + BoxDecoration(color: Colors.green, shape: BoxShape.circle), + ), + color: Colors.red, + interval: Duration(milliseconds: 200), + )), + padding: EdgeInsets.symmetric(vertical: 10), + ), + ClipPath( + child: Shimmer( + child: Container( + child: CustomPaint( + painter: CustomShapePainter(), + ), + width: 100, + height: 100), + color: Colors.yellow, + interval: Duration(milliseconds: 200), + ), + clipper: CustomShapeClipper(), + ) + ])) + ]); + } +} + +class CustomShapePainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + canvas.drawPath(customPath(size), Paint()..color = Colors.cyan); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; } } + +class CustomShapeClipper extends CustomClipper { + @override + Path getClip(Size size) { + return customPath(size); + } + + @override + bool shouldReclip(covariant CustomClipper oldClipper) { + return true; + } +} + +Path customPath(Size size) { + return Path() + ..addRect(Rect.fromCenter( + center: Offset(size.width / 2, size.height / 2), + width: size.width / 2, + height: size.height / 2)) + ..addOval(Rect.fromCenter( + center: Offset(3 * size.width / 4, size.height / 2), + width: size.width / 3, + height: size.height / 3)) + ..addOval(Rect.fromCenter( + center: Offset(size.width / 4, size.height / 2), + width: size.width / 3, + height: size.height / 3)); +} diff --git a/lib/shimmer_animation.dart b/lib/shimmer_animation.dart index 3b7a295..da89185 100644 --- a/lib/shimmer_animation.dart +++ b/lib/shimmer_animation.dart @@ -33,33 +33,36 @@ class Shimmer extends StatelessWidget { /// Accepts a [Duration] that would be the time period of animation. Default value is [Duration(seconds: 3)] final Duration duration; + /// [Duration] before the animation starts. Default value is [null] (no delay) + final Duration? delay; + /// Accepts a [Duration] that would be the interval between the repeating animation. Default value is [Duration(seconds: 0)] i.e. no interval final Duration interval; /// Accepts a [ShimmerDirection] and aligns the animation accordingly. Default value is [ShimmerDirection.fromLBRT()] final ShimmerDirection direction; - Shimmer({ - required this.child, - this.enabled = true, - this.color = Colors.white, - this.colorOpacity = 0.3, - this.duration = const Duration(seconds: 3), - this.interval = const Duration(seconds: 0), - this.direction = const ShimmerDirection.fromLTRB(), - }); + Shimmer( + {required this.child, + this.enabled = true, + this.color = Colors.white, + this.colorOpacity = 0.3, + this.duration = const Duration(seconds: 3), + this.interval = const Duration(seconds: 0), + this.direction = const ShimmerDirection.fromLTRB(), + this.delay}); @override Widget build(BuildContext context) { if (enabled) return ShimmerAnimator( - child: child, - color: color, - opacity: colorOpacity, - duration: duration, - interval: interval, - direction: direction, - ); + child: child, + color: color, + opacity: colorOpacity, + duration: duration, + interval: interval, + direction: direction, + delay: delay); else return child; } @@ -112,6 +115,8 @@ class ShimmerDirection { this.end = Alignment.centerRight, }); + ShimmerDirection.custom({required this.begin, required this.end}); + factory ShimmerDirection() => ShimmerDirection._fromLTRB(); /// Animation starts from Left Top and moves towards the Right Bottom diff --git a/lib/src/shimmer_animator.dart b/lib/src/shimmer_animator.dart index 336dfe3..8d302d6 100644 --- a/lib/src/shimmer_animator.dart +++ b/lib/src/shimmer_animator.dart @@ -7,17 +7,18 @@ class ShimmerAnimator extends StatefulWidget { final double opacity; final Duration duration; final Duration interval; + final Duration? delay; final ShimmerDirection direction; final Widget child; - ShimmerAnimator({ - required this.child, - required this.color, - required this.opacity, - required this.duration, - required this.interval, - required this.direction, - }); + ShimmerAnimator( + {required this.child, + required this.color, + required this.opacity, + required this.duration, + required this.interval, + required this.direction, + this.delay}); @override _ShimmerAnimatorState createState() => _ShimmerAnimatorState(); @@ -43,7 +44,12 @@ class _ShimmerAnimatorState extends State () => mounted ? controller.forward(from: 0) : null); setState(() {}); }); - controller.forward(); + if (widget.delay == null) { + controller.forward(); + } else { + Future.delayed( + widget.delay!, () => mounted ? controller.forward() : null); + } } @override From 35232372c2cdab086b52eef742097d8dd1359a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bel?= Date: Fri, 6 Aug 2021 15:41:59 +0200 Subject: [PATCH 2/2] removed an attempt to have a custom ShimmerDirection --- lib/shimmer_animation.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/shimmer_animation.dart b/lib/shimmer_animation.dart index da89185..d45d151 100644 --- a/lib/shimmer_animation.dart +++ b/lib/shimmer_animation.dart @@ -115,8 +115,6 @@ class ShimmerDirection { this.end = Alignment.centerRight, }); - ShimmerDirection.custom({required this.begin, required this.end}); - factory ShimmerDirection() => ShimmerDirection._fromLTRB(); /// Animation starts from Left Top and moves towards the Right Bottom