Skip to content

Commit 18ef427

Browse files
committed
🔧 Update Pack 2 #11
1 parent 24bcac4 commit 18ef427

File tree

4 files changed

+153
-33
lines changed

4 files changed

+153
-33
lines changed

example/lib/main.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:hyper_effects_demo/stories/scroll_phase_transition.dart';
1515
import 'package:hyper_effects_demo/stories/scroll_wheel_blur.dart';
1616
import 'package:hyper_effects_demo/stories/scroll_wheel_transition.dart';
1717
import 'package:hyper_effects_demo/stories/shake_and_spring_animation.dart';
18+
import 'package:hyper_effects_demo/stories/success_card_animation.dart';
1819
import 'package:hyper_effects_demo/stories/text_animation.dart';
1920
import 'package:hyper_effects_demo/stories/windows_settings_transition.dart';
2021

@@ -83,6 +84,10 @@ class Storyboard extends StatefulWidget {
8384

8485
class _StoryboardState extends State<Storyboard> with WidgetsBindingObserver {
8586
final List<Story> animationStories = [
87+
const Story(
88+
title: 'Success Card Animation',
89+
child: SuccessCardAnimation()
90+
),
8691
const Story(
8792
title: 'Group Animation',
8893
child: GroupAnimation(),

example/lib/stories/shake_and_spring_animation.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class _SpringAnimationState extends State<SpringAnimation> {
2424
.shake()
2525
.animate(
2626
trigger: trigger,
27-
startImmediately: true,
27+
startState: AnimationStartState.playImmediately,
2828
delay: const Duration(seconds: 1),
2929
repeat: -1,
3030
playIf: () => !trigger,
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:hyper_effects/hyper_effects.dart';
3+
4+
class SuccessCardAnimation extends StatefulWidget {
5+
const SuccessCardAnimation({super.key});
6+
7+
@override
8+
State<SuccessCardAnimation> createState() => _SuccessCardAnimationState();
9+
}
10+
11+
class _SuccessCardAnimationState extends State<SuccessCardAnimation> {
12+
bool isCompleted = true;
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return ConstrainedBox(
17+
constraints: const BoxConstraints(
18+
maxWidth: 350,
19+
maxHeight: 200,
20+
),
21+
child: MouseRegion(
22+
cursor: SystemMouseCursors.click,
23+
child: GestureDetector(
24+
onTap: () {
25+
setState(() {
26+
isCompleted = !isCompleted;
27+
});
28+
},
29+
child: Padding(
30+
padding: const EdgeInsets.all(12),
31+
child: Container(
32+
constraints: const BoxConstraints(minHeight: 148),
33+
decoration: BoxDecoration(
34+
color: Colors.white,
35+
borderRadius: BorderRadius.circular(16),
36+
),
37+
child: ClipRRect(
38+
borderRadius: BorderRadius.circular(16),
39+
child: Stack(
40+
alignment: Alignment.center,
41+
fit: StackFit.expand,
42+
children: [
43+
Image.asset(
44+
'assets/fashion/fashion_0.jpg',
45+
fit: BoxFit.cover,
46+
),
47+
Positioned.fill(
48+
child: Container(
49+
decoration: const BoxDecoration(
50+
color: Color(0x3A079455),
51+
),
52+
alignment: Alignment.center,
53+
child: const Icon(
54+
Icons.check_circle,
55+
size: 74,
56+
)
57+
.translateY(
58+
isCompleted ? 0 : 100,
59+
from: isCompleted ? 100 : 0,
60+
)
61+
.animate(
62+
trigger: isCompleted,
63+
startState:
64+
AnimationStartState.useCurrentValues,
65+
curve: !isCompleted
66+
? Curves.easeInBack
67+
: Curves.easeOutBack,
68+
duration: const Duration(
69+
milliseconds: 400,
70+
),
71+
),
72+
)
73+
.opacity(
74+
isCompleted ? 1 : 0,
75+
from: isCompleted ? 0 : 1,
76+
)
77+
.animate(
78+
trigger: isCompleted,
79+
startState:
80+
AnimationStartState.useCurrentValues,
81+
curve: Curves.easeInOutSine,
82+
duration: const Duration(
83+
milliseconds: 400,
84+
),
85+
),
86+
),
87+
],
88+
),
89+
),
90+
),
91+
),
92+
),
93+
),
94+
);
95+
}
96+
}

lib/src/animated_effect.dart

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ extension AnimatedEffectExt on Widget? {
4545
///
4646
/// The [delay] parameter is used to set a delay before the animation starts.
4747
///
48-
/// The [startImmediately] parameter is used to determine whether the
49-
/// animation should be triggered immediately when the widget is built,
50-
/// ignoring the value of [trigger] initially.
48+
/// The [resetValues] parameter is used to determine whether the animation
49+
/// should start from idle values or from the current state of the widget.
50+
///
51+
/// The [startState] parameter is used to determine the behavior of the
52+
/// animation as soon as it is added to the widget tree.
5153
///
5254
/// The [playIf] parameter is used to determine whether the animation should
5355
/// be played or skipped. If the callback returns false, the animation will
@@ -62,11 +64,10 @@ extension AnimatedEffectExt on Widget? {
6264
Curve curve = appleEaseInOut,
6365
int repeat = 0,
6466
bool reverse = false,
65-
bool startImmediately = false,
66-
bool skipFirstTime = false,
6767
bool resetValues = false,
6868
bool waitForLastAnimation = false,
6969
Duration delay = Duration.zero,
70+
AnimationStartState startState = AnimationStartState.idle,
7071
VoidCallback? onEnd,
7172
BooleanCallback? playIf,
7273
BooleanCallback? skipIf,
@@ -78,11 +79,10 @@ extension AnimatedEffectExt on Widget? {
7879
curve: curve,
7980
repeat: repeat,
8081
reverse: reverse,
81-
startImmediately: startImmediately,
82-
skipFirstTime: skipFirstTime,
8382
resetValues: resetValues,
8483
waitForLastAnimation: waitForLastAnimation,
8584
delay: delay,
85+
startState: startState,
8686
onEnd: onEnd,
8787
playIf: playIf,
8888
skipIf: skipIf,
@@ -232,6 +232,26 @@ extension AnimatedEffectExt on Widget? {
232232
Widget resetAll() => ResetAllAnimationsEffect(child: this);
233233
}
234234

235+
/// Determines the behavior of the [AnimatedEffect] as soon as it is added
236+
/// to the widget tree.
237+
enum AnimationStartState {
238+
/// As soon as the animation is inserted into the widget tree, it will
239+
/// start playing the animation from the beginning to the end. Before
240+
/// the trigger Object changes.
241+
playImmediately,
242+
243+
/// The animation will be inserted into the widget tree but will not
244+
/// start playing. It will instead trigger the effects in the chain
245+
/// to their ending values as soon as it is inserted.
246+
/// The "current" values of the effect chain are used
247+
/// immediately as initial values.
248+
useCurrentValues,
249+
250+
/// As soon as the animation is inserted into the widget tree, none of
251+
/// the effects will be triggered in any state.
252+
idle;
253+
}
254+
235255
/// A widget that animates the effects applied to it's child.
236256
class AnimatedEffect extends StatefulWidget {
237257
/// The widget below this widget in the tree.
@@ -244,6 +264,10 @@ class AnimatedEffect extends StatefulWidget {
244264
/// Defines how the animation is fired.
245265
final AnimationTriggerType triggerType;
246266

267+
/// Determines the behavior of this [AnimatedEffect] as soon as it is added
268+
/// to the widget tree.
269+
final AnimationStartState startState;
270+
247271
/// The duration of the animation.
248272
final Duration duration;
249273

@@ -259,12 +283,6 @@ class AnimatedEffect extends StatefulWidget {
259283
/// Whether the animation should be reversed after each repetition.
260284
final bool reverse;
261285

262-
/// Whether the animation should be triggered immediately when the widget is
263-
/// built, ignoring the value of [trigger] initially.
264-
final bool startImmediately;
265-
266-
final bool skipFirstTime;
267-
268286
/// Normally, an effect represents the current state of the widget and this
269287
/// animate effect is only in charge of lerping between states of those
270288
/// effect values.
@@ -299,13 +317,12 @@ class AnimatedEffect extends StatefulWidget {
299317
required this.child,
300318
required this.duration,
301319
required this.triggerType,
320+
this.startState = AnimationStartState.idle,
302321
this.trigger,
303322
this.curve = appleEaseInOut,
304323
this.onEnd,
305324
this.repeat = 0,
306325
this.reverse = false,
307-
this.startImmediately = false,
308-
this.skipFirstTime = false,
309326
this.resetValues = false,
310327
this.waitForLastAnimation = false,
311328
this.delay = Duration.zero,
@@ -339,7 +356,10 @@ class AnimatedEffectState extends State<AnimatedEffect>
339356
/// The animation controller that drives the animation.
340357
late final AnimationController controller = AnimationController(
341358
vsync: this,
342-
value: widget.skipFirstTime || shouldSkip ? 1 : 0,
359+
value:
360+
widget.startState == AnimationStartState.useCurrentValues || shouldSkip
361+
? 1
362+
: 0,
343363
duration: widget.duration,
344364
);
345365

@@ -359,21 +379,21 @@ class AnimatedEffectState extends State<AnimatedEffect>
359379
if (didPlay) return;
360380

361381
if (widget.key case Key key) {
362-
final persister = AnimatedEffectStateRetainer.maybeOf(context);
363-
final alreadyPlayed = persister?.didPlay(key) ?? false;
382+
final retainer = AnimatedEffectStateRetainer.maybeOf(context);
383+
final alreadyPlayed = retainer?.didPlay(key) ?? false;
364384
if (alreadyPlayed) {
365385
// If the animation has already played, end it immediately.
366386
controller.value = 1;
367387
return;
368388
}
369389

370-
persister?.markAsPlayed(key);
390+
retainer?.markAsPlayed(key);
371391
}
372392

373393
// If the trigger type is one shot or trigger immediately is true,
374394
// drive the animation.
375395
if (widget.triggerType == AnimationTriggerType.oneShot ||
376-
widget.startImmediately) {
396+
widget.startState == AnimationStartState.playImmediately) {
377397
drive();
378398
didPlay = false;
379399
}
@@ -431,7 +451,7 @@ class AnimatedEffectState extends State<AnimatedEffect>
431451
// ancestor's [AnimationTriggerType] is
432452
// [AnimationTriggerType.afterLast].
433453
final AnimatedEffectState? parentState =
434-
context.findAncestorStateOfType<AnimatedEffectState>();
454+
context.findAncestorStateOfType<AnimatedEffectState>();
435455
final AnimationTriggerType? triggerType =
436456
parentState?.widget.triggerType;
437457
if (parentState != null &&
@@ -443,7 +463,7 @@ class AnimatedEffectState extends State<AnimatedEffect>
443463
// [ResetAllAnimationsEffect], reset all animations in the chain.
444464
else {
445465
final resetState =
446-
context.findAncestorStateOfType<ResetAllAnimationsEffectState>();
466+
context.findAncestorStateOfType<ResetAllAnimationsEffectState>();
447467
resetState?.reset();
448468
}
449469
}
@@ -500,16 +520,15 @@ class AnimatedEffectState extends State<AnimatedEffect>
500520
Widget build(BuildContext context) {
501521
return AnimatedBuilder(
502522
animation: controller,
503-
builder: (context, child) =>
504-
EffectQuery(
505-
linearValue: controller.value,
506-
curvedValue: widget.curve.transform(controller.value),
507-
isTransition: false,
508-
resetValues: widget.resetValues,
509-
duration: widget.duration,
510-
curve: widget.curve,
511-
child: child!,
512-
),
523+
builder: (context, child) => EffectQuery(
524+
linearValue: controller.value,
525+
curvedValue: widget.curve.transform(controller.value),
526+
isTransition: false,
527+
resetValues: widget.resetValues,
528+
duration: widget.duration,
529+
curve: widget.curve,
530+
child: child!,
531+
),
513532
child: widget.child,
514533
);
515534
}

0 commit comments

Comments
 (0)