Skip to content

Instantly share code, notes, and snippets.

@gbuela
Created April 3, 2019 23:46
Show Gist options
  • Save gbuela/64557c130d62e23d33b3e47d076e95e2 to your computer and use it in GitHub Desktop.
Save gbuela/64557c130d62e23d33b3e47d076e95e2 to your computer and use it in GitHub Desktop.
Card flip animation in Flutter
import 'dart:math';
import 'package:flutter/material.dart';
// based on https://github.com/fedeoo/flip_card/
// provides a callback to the front & back widgets so they can trigger the flip, therefore the CardSideBuilder
// note this version only flips horizontally
class AnimationCard extends StatelessWidget {
AnimationCard({this.child, this.animation});
final Widget child;
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
var transform = Matrix4.identity();
transform.setEntry(3, 2, 0.001);
transform.rotateY(animation.value);
return Transform(
transform: transform,
alignment: Alignment.center,
child: child,
);
},
child: child,
);
}
}
typedef Widget CardSideBuilder(
BuildContext context, VoidCallback toggleCallback);
class FlipCard extends StatefulWidget {
final CardSideBuilder frontBuilder;
final CardSideBuilder backBuilder;
final int speed = 300;
const FlipCard(
{Key key, @required this.frontBuilder, @required this.backBuilder})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _FlipCardState();
}
}
enum FlippingState { Front, FrontOut, BackIn, Back, BackOut, FrontIn }
class _FlipCardState extends State<FlipCard> with TickerProviderStateMixin {
AnimationController controllerFront;
AnimationController controllerBack;
Animation<double> _frontOutRotation;
Animation<double> _backInRotation;
FlippingState _flippingState;
@override
void initState() {
super.initState();
_flippingState = FlippingState.Front;
controllerFront = AnimationController(
duration: Duration(milliseconds: widget.speed), vsync: this);
controllerBack = AnimationController(
duration: Duration(milliseconds: widget.speed), vsync: this);
_frontOutRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween(begin: 0.0, end: pi / 2)
.chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
],
).animate(controllerFront);
_backInRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween(begin: -pi / 2, end: 0.0)
.chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
],
).animate(controllerBack);
}
_toggleCard() {
if (_flippingState == FlippingState.Front) {
setState(() {
_flippingState = FlippingState.FrontOut;
});
} else if (_flippingState == FlippingState.Back) {
setState(() {
_flippingState = FlippingState.BackOut;
});
}
}
Widget _animatedFront(BuildContext context) {
return AnimationCard(
animation: _frontOutRotation,
child: widget.frontBuilder(context, _toggleCard),
);
}
Widget _animatedBack(BuildContext context) {
return AnimationCard(
animation: _backInRotation,
child: widget.backBuilder(context, _toggleCard),
);
}
@override
Widget build(BuildContext context) {
switch (_flippingState) {
case FlippingState.Front:
return widget.frontBuilder(context, _toggleCard);
case FlippingState.Back:
return widget.backBuilder(context, _toggleCard);
case FlippingState.FrontOut:
controllerFront.forward().whenComplete(() {
setState(() {
_flippingState = FlippingState.BackIn;
});
});
return _animatedFront(context);
case FlippingState.BackIn:
controllerBack.forward().whenComplete(() {
setState(() {
_flippingState = FlippingState.Back;
});
});
return _animatedBack(context);
case FlippingState.BackOut:
controllerBack.reverse().whenComplete(() {
setState(() {
_flippingState = FlippingState.FrontIn;
});
});
return _animatedBack(context);
case FlippingState.FrontIn:
controllerFront.reverse().whenComplete(() {
setState(() {
_flippingState = FlippingState.Front;
});
});
return _animatedFront(context);
}
}
@override
void dispose() {
controllerFront.dispose();
controllerBack.dispose();
super.dispose();
}
}
@gbuela
Copy link
Author

gbuela commented Apr 3, 2019

Can it be improved? let me know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment