flutter_phase_animator 0.0.1
flutter_phase_animator: ^0.0.1 copied to clipboard
A Flutter animation package inspired by SwiftUI's PhaseAnimator. Chain steps sequentially or loop through phases declaratively
flutter_phase_animator #
A Flutter animation package inspired by SwiftUI's PhaseAnimator. Chain steps sequentially or loop through phases declaratively — with full playback control.
Installation #
dependencies:
flutter_phase_animator: ^0.0.1
import 'package:flutter_phase_animator/flutter_phase_animator.dart';
PhaseAnimator — chained steps #
Plays a list of AnimationSteps one after another. Each step receives
a t value going from 0.0 to 1.0 that you use to animate any property.
PhaseAnimator(
autoPlay: true,
steps: [
// Step 1: fade in
AnimationStep(
duration: Duration(milliseconds: 400),
curve: Curves.easeIn,
builder: (context, t, child) => Opacity(opacity: t, child: child),
),
// Step 2: slide up
AnimationStep(
duration: Duration(milliseconds: 400),
curve: Curves.easeOut,
builder: (context, t, child) => Transform.translate(
offset: Offset(0, (1 - t) * 40),
child: child,
),
),
// Step 3: scale bounce
AnimationStep(
duration: Duration(milliseconds: 300),
curve: Curves.elasticOut,
builder: (context, t, child) =>
Transform.scale(scale: 0.8 + t * 0.2, child: child),
),
],
child: MyWidget(),
)
PhaseAnimatorLooping — continuous phases #
Cycles through a list of Phase keyframes automatically, interpolating
between each one. Mirrors SwiftUI's PhaseAnimator.
PhaseAnimatorLooping(
phaseDuration: Duration(milliseconds: 600),
phases: [
Phase(opacity: 1.0, scale: 1.0, offset: Offset.zero),
Phase(opacity: 0.6, scale: 1.3, offset: Offset(0, -20)),
Phase(opacity: 1.0, scale: 0.9, offset: Offset(0, 10)),
],
builder: (context, phase, child) => Opacity(
opacity: phase.opacity,
child: Transform.translate(
offset: phase.offset,
child: Transform.scale(scale: phase.scale, child: child),
),
),
child: MyWidget(),
)
Pause and resume #
PhaseAnimatorLooping(
paused: _isPaused, // toggle to pause/resume
phases: [...],
builder: ...,
child: MyWidget(),
)
Combined pattern #
A common pattern: play an entrance sequence once, then start a looping idle.
class _MyWidget extends StatefulWidget { ... }
class _MyWidgetState extends State<_MyWidget> {
bool _entranceDone = false;
@override
Widget build(BuildContext context) {
return PhaseAnimator(
autoPlay: true,
repeatCount: 1,
onComplete: () => setState(() => _entranceDone = true),
steps: [
AnimationStep(
duration: Duration(milliseconds: 600),
curve: Curves.easeOut,
builder: (ctx, t, child) => Opacity(opacity: t, child: child),
),
AnimationStep(
duration: Duration(milliseconds: 500),
curve: Curves.elasticOut,
builder: (ctx, t, child) =>
Transform.scale(scale: t, child: child),
),
],
child: PhaseAnimatorLooping(
paused: !_entranceDone, // starts only after entrance finishes
phases: [
Phase(scale: 1.0, rotation: 0.0),
Phase(scale: 1.05, rotation: 0.05),
Phase(scale: 0.97, rotation: -0.03),
],
builder: (ctx, phase, child) => Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..scale(phase.scale)
..rotateZ(phase.rotation),
child: child,
),
child: MyWidget(),
),
);
}
}