AnimationTimeline.wave constructor
AnimationTimeline.wave({
- required List<
AnimationController> controllers, - Duration gap = Duration.zero,
- Duration crestHold = Duration.zero,
- Duration returnGap = Duration.zero,
- Duration rest = Duration.zero,
- bool repeat = false,
- Object? id,
- String labelBuilder()?,
- void onStepStart(
- int index,
- AnimationTimelineStep step,
- TimelineDirection direction
- void onStepComplete(
- int index,
- AnimationTimelineStep step,
- TimelineDirection direction
Builds a traveling wave across multiple controllers.
The generated sequence is:
- animate each controller forward in index order with optional
gap - optional
crestHold - animate each controller reverse in reverse index order with optional
returnGap - optional
rest
This is useful for marquee highlights, stepped focus sweeps, and left-to-right then right-to-left motion without manually spelling out the mirrored controller choreography.
Implementation
factory AnimationTimeline.wave({
required List<AnimationController> controllers,
Duration gap = Duration.zero,
Duration crestHold = Duration.zero,
Duration returnGap = Duration.zero,
Duration rest = Duration.zero,
bool repeat = false,
Object? id,
String Function(int index, String phase)? labelBuilder,
void Function(
int index,
AnimationTimelineStep step,
TimelineDirection direction,
)?
onStepStart,
void Function(
int index,
AnimationTimelineStep step,
TimelineDirection direction,
)?
onStepComplete,
}) {
if (controllers.isEmpty) {
throw ArgumentError.value(
controllers,
'controllers',
'must not be empty',
);
}
final steps = <AnimationTimelineStep>[];
for (var index = 0; index < controllers.length; index++) {
if (index > 0 && gap > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(
gap,
label: labelBuilder?.call(index, 'gap') ?? 'wave-gap-$index',
),
);
}
steps.add(
AnimationTimelineStep.forward(
controllers[index],
label: labelBuilder?.call(index, 'crest-in') ?? 'wave-in-$index',
),
);
}
if (crestHold > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(
crestHold,
label:
labelBuilder?.call(controllers.length - 1, 'crest-hold') ??
'wave-crest-hold',
),
);
}
for (var offset = 0; offset < controllers.length; offset++) {
final index = controllers.length - 1 - offset;
if (offset > 0 && returnGap > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(
returnGap,
label:
labelBuilder?.call(index, 'return-gap') ??
'wave-return-gap-$index',
),
);
}
steps.add(
AnimationTimelineStep.reverse(
controllers[index],
label: labelBuilder?.call(index, 'crest-out') ?? 'wave-out-$index',
),
);
}
if (rest > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(
rest,
label: labelBuilder?.call(0, 'rest') ?? 'wave-rest',
),
);
}
return AnimationTimeline(
steps: steps,
repeat: repeat,
id: id,
onStepStart: onStepStart,
onStepComplete: onStepComplete,
);
}