Created
November 26, 2019 16:39
-
-
Save brianegan/1349ad435206725bb1f2747cb50cc0cc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter/physics.dart'; | |
main() { | |
runApp(MaterialApp(home: PhysicsCardDragDemo())); | |
} | |
class PhysicsCardDragDemo extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(), | |
body: DraggableCard( | |
child: FlutterLogo( | |
size: 128, | |
), | |
), | |
); | |
} | |
} | |
/// A draggable card that moves back to [Alignment.center] when it's | |
/// released. | |
class DraggableCard extends StatefulWidget { | |
final Widget child; | |
DraggableCard({this.child}); | |
@override | |
_DraggableCardState createState() => _DraggableCardState(); | |
} | |
class _DraggableCardState extends State<DraggableCard> | |
with SingleTickerProviderStateMixin { | |
AnimationController _controller; | |
/// The alignment of the card as it is dragged or being animated. | |
/// | |
/// While the card is being dragged, this value is set to the values computed | |
/// in the GestureDetector onPanUpdate callback. If the animation is running, | |
/// this value is set to the value of the [_animation]. | |
Alignment _dragAlignment = Alignment.center; | |
Animation<Alignment> _animation; | |
/// Calculates and runs a [SpringSimulation]. | |
void _runAnimation(Offset pixelsPerSecond, Size size) { | |
_animation = _controller.drive( | |
AlignmentTween( | |
begin: _dragAlignment, | |
end: Alignment.center, | |
), | |
); | |
// Calculate the velocity relative to the unit interval, [0,1], | |
// used by the animation controller. | |
final unitsPerSecondX = pixelsPerSecond.dx / size.width; | |
final unitsPerSecondY = pixelsPerSecond.dy / size.height; | |
final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY); | |
final unitVelocity = unitsPerSecond.distance; | |
const spring = SpringDescription( | |
mass: 30, | |
stiffness: 1, | |
damping: 1, | |
); | |
final simulation = SpringSimulation(spring, 0, 1, -unitVelocity); | |
_controller.animateWith(simulation); | |
} | |
@override | |
void initState() { | |
super.initState(); | |
_controller = AnimationController(vsync: this); | |
_controller.addListener(() { | |
setState(() { | |
_dragAlignment = _animation.value; | |
}); | |
}); | |
} | |
@override | |
void dispose() { | |
_controller.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final size = MediaQuery.of(context).size; | |
return GestureDetector( | |
onPanDown: (details) { | |
_controller.stop(); | |
}, | |
onPanUpdate: (details) { | |
setState(() { | |
_dragAlignment += Alignment( | |
details.delta.dx / (size.width / 2), | |
details.delta.dy / (size.height / 2), | |
); | |
}); | |
}, | |
onPanEnd: (details) { | |
_runAnimation(details.velocity.pixelsPerSecond, size); | |
}, | |
child: Align( | |
alignment: _dragAlignment, | |
child: Card( | |
child: widget.child, | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment