Skip to content

Commit

Permalink
feat: add AnimatableStatelessWidget (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold committed May 23, 2023
1 parent adf9fb0 commit fd94936
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 134 deletions.
60 changes: 28 additions & 32 deletions packages/fleet/example/lib/stack.dart
Expand Up @@ -5,38 +5,28 @@ void main() {
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
State<MyApp> createState() => _MyAppState();
}

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

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
class _MyAppState extends State<MyApp> {
var _left = true;

@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _left = !_left),
child: Stack(
children: List.generate(
6,
(index) => StackElement(index: index, left: _left),
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _left = !_left),
child: Stack(
children: [
for (var i = 0; i < 6; i++) StackElement(index: i, left: _left)
],
),
),
),
Expand All @@ -45,30 +35,36 @@ class _MyHomePageState extends State<MyHomePage> {
}

class StackElement extends StatelessWidget {
const StackElement({super.key, required this.index, required this.left});
const StackElement({
super.key,
required this.index,
required this.left,
});

static const _stackDimension = 500.0;
static const _step = 70.0;

final int index;
final bool left;

AnimationSpec _buildAnimation() {
return AnimationSpec.curve(Curves.easeInOutCubic, 500.ms - 25.ms * index)
.delay(50.ms * index);
}
AnimationSpec _buildAnimation() =>
AnimationSpec.curve(Curves.easeInOutCubic, 500.ms - 25.ms * index)
.delay(50.ms * index);

Color _buildColor() =>
HSLColor.fromAHSL(1, ((index * 12) + 155) % 360.0, 1, .5).toColor();

@override
Widget build(BuildContext context) {
final dimension = 500.0 - (index * 70);
final elementDimension = _stackDimension - (index * _step);
return Material(
elevation: 50,
color: _buildColor(),
borderRadius: BorderRadius.circular(dimension / 20),
borderRadius: BorderRadius.circular(elementDimension / 20),
)
.square(dimension)
.square(elementDimension)
.center()
.square(500)
.square(_stackDimension)
.align(Alignment(left ? -.5 : .5, 0))
.animation(_buildAnimation(), value: left);
}
Expand Down
1 change: 1 addition & 0 deletions packages/fleet/lib/fleet.dart
Expand Up @@ -15,6 +15,7 @@ export 'src/animatable_render_object_widget.dart'
show
AnimatableRenderObjectWidget,
AnimatableSingleChildRenderObjectWidgetMixin;
export 'src/animatable_stateless_widget.dart' show AnimatableStatelessWidget;
export 'src/animatable_widget_state.dart'
show AnimatableState, AnimatableStateMixin;
export 'src/animate.dart' show Animated, withAnimation, AnimatingStateMixin;
Expand Down
214 changes: 112 additions & 102 deletions packages/fleet/lib/src/animatable_flutter_widgets.dart
Expand Up @@ -6,7 +6,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

import 'animatable_render_object_widget.dart';
import 'animatable_widget_state.dart';
import 'animatable_stateless_widget.dart';
import 'parameter.dart';

typedef _AlignAnimatableParameters = ({
Expand Down Expand Up @@ -67,7 +67,7 @@ class AAlign extends Align
/// Animatable version of [ColoredBox].
///
/// {@category Animatable Flutter widget}
class AColoredBox extends StatefulWidget {
class AColoredBox extends AnimatableStatelessWidget<AnimatableColor> {
/// Creates an animatable version of [ColoredBox].
const AColoredBox({super.key, required this.color, this.child});

Expand All @@ -78,30 +78,41 @@ class AColoredBox extends StatefulWidget {
final Widget? child;

@override
State<AColoredBox> createState() => _AColoredBoxState();
}

class _AColoredBoxState extends AnimatableState<AColoredBox> {
late final _color = AnimatableColor(widget.color, host: this);
AnimatableColor createAnimatableParameters(AnimatableParameterHost host) {
return AnimatableColor(color, host: host);
}

@override
void updateAnimatableParameters() {
_color.value = widget.color;
void updateAnimatableParameters(AnimatableColor parameters) {
parameters.value = color;
}

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, AnimatableColor? parameters) {
return ColoredBox(
color: _color.animatedValue,
child: widget.child,
color: parameters?.animatedValue ?? color,
child: child,
);
}
}

typedef _ContainerAnimatableParameters = ({
OptionalAnimatableAlignmentGeometry alignment,
OptionalAnimatableEdgeInsetsGeometry padding,
OptionalAnimatableColor color,
OptionalAnimatableDecoration decoration,
OptionalAnimatableDecoration foregroundDecoration,
OptionalAnimatableBoxConstraints constraints,
OptionalAnimatableEdgeInsetsGeometry margin,
OptionalAnimatableMatrix4 transform,
OptionalAnimatableAlignmentGeometry transformAlignment,
});

/// Animatable version of [Container].
///
/// {@category Animatable Flutter widget}
class AContainer extends StatefulWidget {
class AContainer
extends AnimatableStatelessWidget<_ContainerAnimatableParameters> {
/// Creates an animatable version of [Container].
AContainer({
super.key,
Expand Down Expand Up @@ -157,74 +168,57 @@ class AContainer extends StatefulWidget {
final Widget? child;

@override
State<AContainer> createState() => _AContainerState();
}
_ContainerAnimatableParameters createAnimatableParameters(
AnimatableParameterHost host,
) {
return (
alignment: OptionalAnimatableAlignmentGeometry(alignment, host: host),
padding: OptionalAnimatableEdgeInsetsGeometry(padding, host: host),
color: OptionalAnimatableColor(color, host: host),
decoration: OptionalAnimatableDecoration(decoration, host: host),
foregroundDecoration:
OptionalAnimatableDecoration(foregroundDecoration, host: host),
constraints: OptionalAnimatableBoxConstraints(constraints, host: host),
margin: OptionalAnimatableEdgeInsetsGeometry(margin, host: host),
transform: OptionalAnimatableMatrix4(transform, host: host),
transformAlignment:
OptionalAnimatableAlignmentGeometry(transformAlignment, host: host),
);
}

class _AContainerState extends AnimatableState<AContainer> {
late final _alignment = OptionalAnimatableAlignmentGeometry(
widget.alignment,
host: this,
);
late final _padding = OptionalAnimatableEdgeInsetsGeometry(
widget.padding,
host: this,
);
late final _color = OptionalAnimatableColor(
widget.color,
host: this,
);
late final _decoration = OptionalAnimatableDecoration(
widget.decoration,
host: this,
);
late final _foregroundDecoration = OptionalAnimatableDecoration(
widget.foregroundDecoration,
host: this,
);
late final _constraints = OptionalAnimatableBoxConstraints(
widget.constraints,
host: this,
);
late final _margin = OptionalAnimatableEdgeInsetsGeometry(
widget.margin,
host: this,
);
late final _transform = OptionalAnimatableMatrix4(
widget.transform,
host: this,
);
late final _transformAlignment = OptionalAnimatableAlignmentGeometry(
widget.transformAlignment,
host: this,
);

@override
void updateAnimatableParameters() {
_alignment.value = widget.alignment;
_padding.value = widget.padding;
_color.value = widget.color;
_decoration.value = widget.decoration;
_foregroundDecoration.value = widget.foregroundDecoration;
_constraints.value = widget.constraints;
_margin.value = widget.margin;
_transform.value = widget.transform;
_transformAlignment.value = widget.transformAlignment;
@override
void updateAnimatableParameters(_ContainerAnimatableParameters parameters) {
parameters
..alignment.value = alignment
..padding.value = padding
..color.value = color
..decoration.value = decoration
..foregroundDecoration.value = foregroundDecoration
..constraints.value = constraints
..margin.value = margin
..transform.value = transform
..transformAlignment.value = transformAlignment;
}

@override
Widget build(BuildContext context) {
Widget build(
BuildContext context,
_ContainerAnimatableParameters? parameters,
) {
return Container(
alignment: _alignment.animatedValue,
padding: _padding.animatedValue,
color: _color.animatedValue,
decoration: _decoration.animatedValue,
foregroundDecoration: _foregroundDecoration.animatedValue,
constraints: _constraints.animatedValue,
margin: _margin.animatedValue,
transform: _transform.animatedValue,
transformAlignment: _transformAlignment.animatedValue,
clipBehavior: widget.clipBehavior,
child: widget.child,
alignment: parameters?.alignment.animatedValue ?? alignment,
padding: parameters?.padding.animatedValue ?? padding,
color: parameters?.color.animatedValue ?? color,
decoration: parameters?.decoration.animatedValue ?? decoration,
foregroundDecoration: parameters?.foregroundDecoration.animatedValue ??
foregroundDecoration,
constraints: parameters?.constraints.animatedValue ?? constraints,
margin: parameters?.margin.animatedValue ?? margin,
transform: parameters?.transform.animatedValue ?? transform,
transformAlignment:
parameters?.transformAlignment.animatedValue ?? transformAlignment,
clipBehavior: clipBehavior,
child: child,
);
}
}
Expand Down Expand Up @@ -304,10 +298,20 @@ class APadding extends Padding
}
}

typedef _PositionedAnimatableParameters = ({
OptionalAnimatableDouble left,
OptionalAnimatableDouble top,
OptionalAnimatableDouble right,
OptionalAnimatableDouble bottom,
OptionalAnimatableDouble width,
OptionalAnimatableDouble height,
});

/// Animatable version of [Positioned].
///
/// {@category Animatable Flutter widget}
class APositioned extends StatefulWidget {
class APositioned
extends AnimatableStatelessWidget<_PositionedAnimatableParameters> {
/// Creates an animatable version of [Positioned].
const APositioned({
super.key,
Expand Down Expand Up @@ -414,37 +418,43 @@ class APositioned extends StatefulWidget {
final Widget child;

@override
State<APositioned> createState() => _APositionedState();
}

class _APositionedState extends AnimatableState<APositioned> {
late final _left = OptionalAnimatableDouble(widget.left, host: this);
late final _top = OptionalAnimatableDouble(widget.top, host: this);
late final _right = OptionalAnimatableDouble(widget.right, host: this);
late final _bottom = OptionalAnimatableDouble(widget.bottom, host: this);
late final _width = OptionalAnimatableDouble(widget.width, host: this);
late final _height = OptionalAnimatableDouble(widget.height, host: this);
_PositionedAnimatableParameters createAnimatableParameters(
AnimatableParameterHost host,
) {
return (
left: OptionalAnimatableDouble(left, host: host),
top: OptionalAnimatableDouble(top, host: host),
right: OptionalAnimatableDouble(right, host: host),
bottom: OptionalAnimatableDouble(bottom, host: host),
width: OptionalAnimatableDouble(width, host: host),
height: OptionalAnimatableDouble(height, host: host),
);
}

@override
void updateAnimatableParameters() {
_left.value = widget.left;
_top.value = widget.top;
_right.value = widget.right;
_bottom.value = widget.bottom;
_width.value = widget.width;
_height.value = widget.height;
void updateAnimatableParameters(_PositionedAnimatableParameters parameters) {
parameters
..left.value = left
..top.value = top
..right.value = right
..bottom.value = bottom
..width.value = width
..height.value = height;
}

@override
Widget build(BuildContext context) {
Widget build(
BuildContext context,
_PositionedAnimatableParameters? parameters,
) {
return Positioned(
left: _left.animatedValue,
top: _top.animatedValue,
right: _right.animatedValue,
bottom: _bottom.animatedValue,
width: _width.animatedValue,
height: _height.animatedValue,
child: widget.child,
left: parameters?.left.animatedValue ?? left,
top: parameters?.top.animatedValue ?? top,
right: parameters?.right.animatedValue ?? right,
bottom: parameters?.bottom.animatedValue ?? bottom,
width: parameters?.width.animatedValue ?? width,
height: parameters?.height.animatedValue ?? height,
child: child,
);
}
}
Expand Down

0 comments on commit fd94936

Please sign in to comment.