AnimationTimeline.accordion constructor
AnimationTimeline.accordion({
- 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 pairwise accordion choreography expanding from the center.
Controllers are grouped into symmetric pairs around the center and each pair animates together on the outward sweep. The return sweep reverses the pair order back toward the center.
This is useful for centered panel reveals, mirrored lane emphasis, and accordion-style motion where left/right counterparts should move as one.
Implementation
factory AnimationTimeline.accordion({
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 groups = <List<int>>[];
final centerLeft = (controllers.length - 1) ~/ 2;
final centerRight = controllers.length ~/ 2;
if (centerLeft == centerRight) {
groups.add([centerLeft]);
} else {
groups.add([centerLeft, centerRight]);
}
for (
var distance = 1;
groups.expand((group) => group).length < controllers.length;
distance++
) {
final left = centerLeft - distance;
final right = centerRight + distance;
final group = <int>[];
if (left >= 0) {
group.add(left);
}
if (right < controllers.length) {
group.add(right);
}
if (group.isNotEmpty) {
groups.add(group);
}
}
final steps = <AnimationTimelineStep>[];
for (var groupIndex = 0; groupIndex < groups.length; groupIndex++) {
final group = groups[groupIndex];
if (groupIndex > 0 && gap > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(gap, label: 'accordion-gap-$groupIndex'),
);
}
steps.add(
AnimationTimelineStep.parallel([
for (final index in group)
AnimationTimelineStep.forward(
controllers[index],
label: labelBuilder?.call(index, 'in') ?? 'accordion-in-$index',
),
], label: 'accordion-expand-$groupIndex'),
);
}
if (crestHold > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(crestHold, label: 'accordion-crest-hold'),
);
}
for (var groupIndex = groups.length - 1; groupIndex >= 0; groupIndex--) {
final group = groups[groupIndex];
if (groupIndex < groups.length - 1 && returnGap > Duration.zero) {
steps.add(
AnimationTimelineStep.delay(
returnGap,
label: 'accordion-return-gap-$groupIndex',
),
);
}
steps.add(
AnimationTimelineStep.parallel([
for (final index in group)
AnimationTimelineStep.reverse(
controllers[index],
label: labelBuilder?.call(index, 'out') ?? 'accordion-out-$index',
),
], label: 'accordion-collapse-$groupIndex'),
);
}
if (rest > Duration.zero) {
steps.add(AnimationTimelineStep.delay(rest, label: 'accordion-rest'));
}
return AnimationTimeline(
steps: steps,
repeat: repeat,
id: id,
onStepStart: onStepStart,
onStepComplete: onStepComplete,
);
}