From a56b4be392967d588d89807bd4206ea8c2e5bb2e Mon Sep 17 00:00:00 2001 From: Neander Date: Thu, 26 Sep 2024 11:07:28 +0900 Subject: [PATCH 1/2] Added ShimmerMode and beginDelay Duration parameters. --- lib/shimmer_animation.dart | 13 ++++++++++ lib/src/custom_shimmer_animation.dart | 2 +- lib/src/shimmer_animator.dart | 36 +++++++++++++++++++-------- lib/src/shimmer_mode.dart | 8 ++++++ 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 lib/src/shimmer_mode.dart diff --git a/lib/shimmer_animation.dart b/lib/shimmer_animation.dart index 1c364a3..2eafec1 100644 --- a/lib/shimmer_animation.dart +++ b/lib/shimmer_animation.dart @@ -2,6 +2,9 @@ library shimmer_animation; import 'package:flutter/material.dart'; import 'package:shimmer_animation/src/shimmer_animator.dart'; +import 'package:shimmer_animation/src/shimmer_mode.dart'; + +export 'src/shimmer_mode.dart' show ShimmerMode; /// Creates simple yet beautiful shimmer animations /// @@ -36,9 +39,15 @@ class Shimmer extends StatelessWidget { /// 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 [Duration] that would be the delay time to begin animation. Default value is [Duration(seconds: 0)] i.e. no beginDelay + final Duration beginDelay; + /// Accepts a [ShimmerDirection] and aligns the animation accordingly. Default value is [ShimmerDirection.fromLBRT()] final ShimmerDirection direction; + /// Accepts a [ShimmerMode] that could be set to either one-shot or repeat mode. Default value is [ShimmerMode.repeat] + final ShimmerMode mode; + Shimmer({ required this.child, this.enabled = true, @@ -46,7 +55,9 @@ class Shimmer extends StatelessWidget { this.colorOpacity = 0.3, this.duration = const Duration(seconds: 3), this.interval = const Duration(seconds: 0), + this.beginDelay = const Duration(seconds: 0), this.direction = const ShimmerDirection.fromLTRB(), + this.mode = ShimmerMode.repeat }); @override @@ -58,7 +69,9 @@ class Shimmer extends StatelessWidget { opacity: colorOpacity, duration: duration, interval: interval, + beginDelay: beginDelay, direction: direction, + mode: mode, ); } else { return child; diff --git a/lib/src/custom_shimmer_animation.dart b/lib/src/custom_shimmer_animation.dart index e1fa890..a956ad2 100644 --- a/lib/src/custom_shimmer_animation.dart +++ b/lib/src/custom_shimmer_animation.dart @@ -58,5 +58,5 @@ class CustomSplashAnimation extends CustomPainter { } @override - bool shouldRepaint(CustomPainter oldDelegate) => true; + bool shouldRepaint(CustomSplashAnimation oldDelegate) => oldDelegate.position != position; } diff --git a/lib/src/shimmer_animator.dart b/lib/src/shimmer_animator.dart index 5d22cd4..2cbb757 100644 --- a/lib/src/shimmer_animator.dart +++ b/lib/src/shimmer_animator.dart @@ -3,13 +3,16 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:shimmer_animation/shimmer_animation.dart'; import 'package:shimmer_animation/src/custom_shimmer_animation.dart'; +import 'package:shimmer_animation/src/shimmer_mode.dart'; class ShimmerAnimator extends StatefulWidget { final Color color; final double opacity; final Duration duration; final Duration interval; + final Duration beginDelay; final ShimmerDirection direction; + final ShimmerMode mode; final Widget child; ShimmerAnimator({ @@ -18,7 +21,9 @@ class ShimmerAnimator extends StatefulWidget { required this.opacity, required this.duration, required this.interval, + required this.beginDelay, required this.direction, + required this.mode, }); @override @@ -31,28 +36,27 @@ class _ShimmerAnimatorState extends State late Animation animation; late AnimationController controller; Timer? timer; + late bool isRepeat; @override void initState() { super.initState(); + isRepeat = widget.mode == ShimmerMode.repeat; + controller = AnimationController(vsync: this, duration: widget.duration); animation = Tween(begin: 0, end: 1).animate(CurvedAnimation( parent: controller, curve: Interval(0, 0.6, curve: Curves.decelerate), )) - ..addListener(() async { - if (controller.isCompleted) { - timer = Timer(widget.interval, - () => mounted ? controller.forward(from: 0) : null); - } - setState(() {}); - }); - controller.forward(); + ..addListener(animationEventListener); + Future.delayed(widget.beginDelay, () => controller.forward(),); } @override void dispose() { - controller.dispose(); + controller + ..removeListener(animationEventListener) + ..dispose(); timer?.cancel(); timer = null; super.dispose(); @@ -60,7 +64,7 @@ class _ShimmerAnimatorState extends State @override Widget build(BuildContext context) { - return CustomPaint( + return controller.isAnimating ? CustomPaint( foregroundPainter: CustomSplashAnimation( context: context, position: animation.value, @@ -70,6 +74,16 @@ class _ShimmerAnimatorState extends State end: widget.direction.end, ), child: widget.child, - ); + ) : widget.child; + } + + void animationEventListener() { + if (controller.isCompleted) { + if (isRepeat) { + timer = Timer(widget.interval, + () => mounted ? controller.forward(from: 0) : null); + } + } + setState(() {}); } } diff --git a/lib/src/shimmer_mode.dart b/lib/src/shimmer_mode.dart new file mode 100644 index 0000000..3b620ae --- /dev/null +++ b/lib/src/shimmer_mode.dart @@ -0,0 +1,8 @@ +/// [oneShot] Shimmer Effect playing only one. +/// +/// [repeat] Shimmer Effect playing continue re-play(default). +/// +enum ShimmerMode { + oneShot, + repeat, +} \ No newline at end of file From 0d9aa16b0d050ddc82e119401ee35468f3c33541 Mon Sep 17 00:00:00 2001 From: Neander Date: Thu, 26 Sep 2024 11:18:30 +0900 Subject: [PATCH 2/2] Added example code. - Tried define ShimmerMode.oneShot, beginDelay parameter in Shimmer. --- example/lib/main.dart | 66 ++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index de5638e..57c8472 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -19,26 +19,58 @@ class FullPageShimmerExample extends StatelessWidget { class ShimmerPage extends StatelessWidget { const ShimmerPage({super.key}); + final _textStyle = const TextStyle( + color: Colors.white, + fontSize: 21.0, + fontWeight: FontWeight.w400 + ); + @override Widget build(BuildContext context) { return Scaffold( - body: Shimmer( - // This is the ONLY required parameter - duration: const Duration(seconds: 3), - // This is NOT the default value. Default value: Duration(seconds: 0) - interval: const 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: const ShimmerDirection.fromLTRB(), - // This is the ONLY required parameter - child: Container( - color: Colors.deepPurple, - ), + body: Column( + children: [ + Expanded( + child: Shimmer( + // This is the ONLY required parameter + duration: const Duration(seconds: 3), + // This is NOT the default value. Default value: Duration(seconds: 0) + interval: const Duration(milliseconds: 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: const ShimmerDirection.fromLTRB(), + // This is the ONLY required parameter + child: Container( + color: Colors.deepPurple, + ), + ) + ), + Expanded( + child: Stack( + children: [ + Shimmer( + duration: const Duration(seconds: 5), + beginDelay: const Duration(seconds: 2), + mode: ShimmerMode.oneShot, + child: Container( + color: Colors.deepOrange, + ), + ), + Padding( + padding: const EdgeInsets.all(12.0), + child: Text("mode: ShimmerMode.oneShot\nbeginDelay: const Duration(seconds: 2)", + style: _textStyle, + ), + ) + ], + ), + ) + ], ), ); }