Skip to content

Instantly share code, notes, and snippets.

@lecuseasar
Created March 5, 2021 19:44
Show Gist options
  • Save lecuseasar/29abd49ba555b19edbaa9fa9caa55e32 to your computer and use it in GitHub Desktop.
Save lecuseasar/29abd49ba555b19edbaa9fa9caa55e32 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: PhysicsCardDrag(),
);
}
}
class PhysicsCardDrag extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Stack(
children: [
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.topLeft,
),
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.topCenter,
),
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.topRight,
),
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.bottomLeft,
),
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.bottomCenter,
),
DraggableCard(
child: FlutterLogo(size: 256),
endAlignment: Alignment.bottomRight,
),
],
),
);
}
}
/// A draggable card that moves back to [Alignment.center] when it's
/// released.
class DraggableCard extends StatefulWidget {
final Widget child;
final Alignment endAlignment;
const DraggableCard({
Key key,
this.child,
this.endAlignment,
}) : super(key: key);
@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;
void _runAnimation(Offset pixelsPerSecond, Size size) {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: widget.endAlignment,
),
);
// _controller.reset();
// _controller.forward();
// 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(
// * change
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, duration: Duration(seconds: 1));
_controller.addListener(() {
setState(() {
_dragAlignment = _animation.value;
});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
var 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