Animation을 이용하여 widget이 스프링처럼 움직이도록 하는 방법에 대해서 알아보겠습니다.
DraggableCard 라는 widget을 만들고, AnimationController 를 생성합니다.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: PhysicsCardDragDemo()));
}
class PhysicsCardDragDemo extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: DraggableCard(
child: FlutterLogo(
size: 128,
),
),
);
}
}
class DraggableCard extends StatefulWidget {
final Widget child;
DraggableCard({required this.child});
_DraggableCardState createState() => _DraggableCardState();
}
class _DraggableCardState extends State<DraggableCard> with SingleTickerProviderStateMixin {
AnimationController _controller;
void initState() {
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
}
void dispose() {
_controller.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Align(
child: Card(
child: widget.child,
),
);
}
}
- Alignment를 추가합니다.
- Drag를 했을때, widget이 움직이도록 합니다.
- GestureDetector 의 onPanDown, onPanUpdate, onPanEnd 를 이용합니다.
class _DraggableCardState extends State<DraggableCard> with SingleTickerProviderStateMixin {
AnimationController _controller;
Alignment _dragAlignment = Alignment.center;
build(BuildContext context) {
var size = MediaQuery.of(context).size;
return GestureDetector(
onPanDown: (details) {},
onPanUpdate: (details) {
setState(() {
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
});
},
onPanEnd: (details) {},
child: Align(
alignment: _dragAlignment,
child: Card(
child: widget.child,
),
),
);
}
Widget
- Animation을 이용해서 widget이 스프링처럼 움직이도록 합니다.
- Animation< Alignment > 와 _runAnimation 함수를 추가합니다.
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Alignment _dragAlignment = Alignment.center;
Animation<Alignment> _animation;
void _runAnimation() {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
_controller.reset();
_controller.forward();
}
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_controller.addListener(() {
setState(() {
_dragAlignment = _animation.value;
});
});
super.initState();
}
- 스프링 모션을 위한 속도를 계산합니다.
- AnimationController 는 animateWith() 함수를 가지고있고, 여기서 SpringSimulation 을 사용할 수 있습니다.
content_copy
/// 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);
}
onPanEnd: (details) {
_runAnimation(details.velocity.pixelsPerSecond, size);
}