Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions packages/fleet/example/lib/graph.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import 'package:fleet/fleet.dart';
import 'package:flutter/material.dart' hide Action;

import 'app.dart';

final _scale = TweenValue.double$(value: 1, name: 'scale');
final _rotation = TweenValue.double$(name: 'rotation');
final _opacity = TweenValue.double$(value: 1, name: 'opacity');
final _color = TweenValue.color(value: Colors.pink, name: 'color');
final _offset = TweenValue.offset(name: 'offset');

AnimationNode _buildAnimation() {
// An animation graph is an immutable data structure that represents an
// animation. It is built by composing animation nodes. Group runs its
// children in parallel, Sequence runs its children in sequence.
return ValueAnimationDefaults(
curve: Curves.ease,
Sequence([
// Here we reset all animated values to their default value.
// This is necessary, in case the animation has already been run, because
// the animated values are not reset automatically.
// Unless `AnimatedValue.to(from: ...)` is specified, the animation of
// that value starts from the value that was last set, either by an
// animation or directly.
Group([
_scale.jump(1),
_rotation.jump(0),
_opacity.jump(1),
_color.jump(Colors.pink),
_offset.jump(Offset.zero),
]),
Group([
_scale.to(2, over: 300.ms),
_rotation.to(.25, over: 300.ms),
_opacity.to(1, from: 0, over: 200.ms, curve: Curves.linear),
]),
Pause(500.ms),
Group([
_color.to(Colors.teal, over: 500.ms, curve: Curves.linear),
_scale.to(1, over: 500.ms),
_offset.to(const Offset(300, 0), over: 500.ms).delay(200.ms),
_opacity.to(0, over: 1.s, curve: Curves.linear).delay(300.ms),
]),
// ignore: avoid_print
Action(() => print('Animation completed')),
]),
)
// The speed of all nodes in the animation graph can be adjusted by
// this single call. This is useful for debugging purposes.
.speed(1);
}

void main() {
runApp(const ExampleApp(page: Page()));
}

class Page extends StatefulWidget {
const Page({super.key});

@override
State<Page> createState() => _PageState();
}

class _PageState extends State<Page>
with TickerProviderStateMixin, AnimationGraphMixin {
void _animate() {
// Cancel all running animations before starting a new one, in case the
// previous animation has not completed. If two animations are run in
// parallel that affect the same value, the result can be unpredictable.
cancelAllAnimations();
animate(_buildAnimation());
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Stack(
alignment: Alignment.center,
children: [
TranslateTransition(
offset: _offset,
child: RotationTransition(
turns: _rotation,
child: ScaleTransition(
scale: _scale,
child: FadeTransition(
opacity: _opacity,
child: _ColoredSquare(color: _color),
),
),
),
),
ElevatedButton(
onPressed: _animate,
child: const Text('Animate'),
),
],
),
),
);
}
}

class _ColoredSquare extends StatelessWidget {
const _ColoredSquare({required this.color});

final Value<Color> color;

@override
Widget build(BuildContext context) {
return SizedBox.square(
dimension: 200,
child: ValueListenableBuilder(
valueListenable: color,
builder: (context, color, _) {
return ColoredBox(color: color);
},
),
);
}
}

class TranslateTransition extends AnimatedWidget {
const TranslateTransition({
super.key,
required Animation<Offset> offset,
required this.child,
}) : super(listenable: offset);

Animation<Offset> get offset => listenable as Animation<Offset>;

final Widget? child;

@override
Widget build(BuildContext context) {
return Transform.translate(
offset: offset.value,
child: child,
);
}
}
43 changes: 43 additions & 0 deletions packages/fleet/example/lib/succes_graph.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ignore_for_file: lines_longer_than_80_chars

// SimpleAnimation(SuccessAnimation.miniGameProgressOpacity, 0.4, 0.5),
// SimpleAnimation(SuccessAnimation.overlayOpacity, 0.4, 0.7, curve: Curves.easeOut),
// SimpleAnimation(SuccessAnimation.cheerOpacity, 0.9, 1.2, curve: Curves.easeOut),
// SimpleAnimation(SuccessAnimation.primaryButtonScale, 0.9, 1.2, curve: Curves.easeOutBack),
// SimpleAnimation(SuccessAnimation.secondaryButtonScale, 1.1, 1.4, curve: Curves.easeOutBack),

import 'package:fleet/fleet.dart';
import 'package:flutter/material.dart';

abstract final class SuccessAnimation {
static final miniGameProgressOpacity = TweenValue.double$();
static final overlayOpacity = TweenValue.double$();
static final cheerOpacity = TweenValue.double$();
static final primaryButtonScale = TweenValue.double$();
static final secondaryButtonScale = TweenValue.double$();

AnimationNode enterAnimation() {
return ValueAnimationDefaults(
curve: Curves.easeOut,
duration: 300.ms,
Sequence([
Pause(400.ms),
Group([
miniGameProgressOpacity.forward(over: 100.ms, curve: Curves.linear),
overlayOpacity.forward(),
]),
Pause(300.ms),
Group([
cheerOpacity.forward(),
ValueAnimationDefaults(
curve: Curves.easeOutBack,
Group(stagger: 200.ms, [
primaryButtonScale.forward(),
secondaryButtonScale.forward(),
]),
),
]),
]),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1430;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
6 changes: 5 additions & 1 deletion packages/fleet/example/macos/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import Cocoa
import FlutterMacOS

@NSApplicationMain
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}

override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
21 changes: 21 additions & 0 deletions packages/fleet/lib/fleet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ export 'src/animation/animate.dart'
export 'src/animation/animation.dart'
show AnimationFromCurveExtension, AnimationSpec;
export 'src/animation/duration.dart' show DurationFromIntExtension;
export 'src/animation/graph.dart'
show
Action,
AnimationElement,
AnimationGraphController,
AnimationGraphMixin,
AnimationNode,
AnimationNodeExtension,
Delay,
DoubleTweenValueExtension,
GraphAnimation,
Group,
OnExitCallback,
Pause,
Sequence,
Speed,
TweenValue,
TweenValueAnimation,
Value,
ValueAnimationDefaults,
ValueJump;
export 'src/animation/parameter.dart'
show
AnimatableAlignmentGeometry,
Expand Down
18 changes: 12 additions & 6 deletions packages/fleet/lib/src/animation/animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,14 @@ abstract class AnimationImpl<T> with Diagnosticable {

var elapsedForRepeat = elapsedForAllRepeats - _lastRepeatEnd;

var isDone = false;

void onFinishRepeat() {
if (!_spec._repeatForever && ++_repeat >= _spec._repeatCount) {
isDone = true;
}
}

if (_forward) {
final endDelta = isAtEnd(elapsedForRepeat);
if (endDelta != null) {
Expand All @@ -441,7 +449,7 @@ abstract class AnimationImpl<T> with Diagnosticable {
_forward = false;
}

_onFinishRepeat();
onFinishRepeat();
}
} else {
elapsedForRepeat = _lastRepeatDuration - elapsedForRepeat;
Expand All @@ -452,11 +460,11 @@ abstract class AnimationImpl<T> with Diagnosticable {

_forward = true;

_onFinishRepeat();
onFinishRepeat();
}
}

if (_isStopped) {
if (isDone) {
// On the last tick we need to be exactly at the end of the animation.
// If the animation is repeated and reversing it is possible that the
// last tick is at the beginning of the animation.
Expand All @@ -466,10 +474,8 @@ abstract class AnimationImpl<T> with Diagnosticable {
}

onChange?.call();
}

void _onFinishRepeat() {
if (!_spec._repeatForever && ++_repeat >= _spec._repeatCount) {
if (isDone) {
stop();
}
}
Expand Down
Loading
Loading