Physics Simulation dalam Flutter adalah cara yang tepat untuk menganimasikan komponen aplikasi flutter agar terlihat lebih realistis dan interaktif. Ini dapat digunakan untuk membuat berbagai macam animasi seperti object jatuh karena gravitasi hingga membuat wadah terlihat terhubung dengan pegas. Dalam artikel ini, kita akan mengeksplorasi hal tersebut dengan membangun aplikasi sederhana.
Ikuti langkah-langkah di bawah ini untuk menggunakan Physics Simulation dalam sebuah Widget:
- Mengembangkan AnimationController
- Menggunakan gestures untuk pergerakan
- Menampilkan animasi
- Menggunakan velocity untuk mensimulasikan gerakan pegas
Mari kita bahas secara detail:
Mengembangkan Animation Controller
Untuk membuat Animation Controller, buat StatefulWidget yang disebut DraggableCard seperti yang ditunjukkan di bawah ini:
import 'package:flutter/material.dart';
main() {
runApp(const MaterialApp(home: PhysicsCardDragDemo()));
}
class PhysicsCardDragDemo extends StatelessWidget {
const PhysicsCardDragDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const DraggableCard(
child: FlutterLogo(
size: 128,
),
),
);
}
}
class DraggableCard extends StatefulWidget {
final Widget child;
const DraggableCard({super.key, required this.child});
@override
State createState() => _DraggableCardState();
}
class _DraggableCardState extends State {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Align(
child: Card(
child: widget.child,
),
);
}
}
Menggunakan Gestures untuk Pergerakan
Di sini kita akan membuat widget bergerak ketika di tarik ke arah mana saja. Pergerakan dapat dipetakan menggunakan GestureDetector yang menangani onPanEnd, onPanUpdate, dan onPanDown seperti yang ditunjukkan di bawah ini:
@override
Widget 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,
),
),
);
}
Menampilkan Animasi
Gunakan kolom Animation<Alignment> dan fungsi _runAnimation untuk menghasilkan efek seperti pegas seperti yang ditunjukkan di bawah ini untuk menampilkan Animasi:
Animation _animation;
void _runAnimation() {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
_controller.reset();
_controller.forward();
}
Sekarang, setiap kali AnimationController menghasilkan pembaruan nilai, perbarui bidang _dragAlignment seperti yang ditunjukkan di bawah ini:
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
_controller.addListener(() {
setState(() {
_dragAlignment = _animation.value;
});
});
}
Lalu sekarang, gunakan bidang _dragAlignment untuk melakukan penyelarasan widget seperti yang ditunjukkan di bawah ini:
child: Align(
alignment: _dragAlignment,
child: Card(
child: widget.child,
),
),
Terakhir, animasi dapat dikelola menggunakan GestureDetector sebagai berikut:
onPanDown: (details) {
_controller.stop();
},
onPanUpdate: (details) {
setState(() {
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
});
},
onPanEnd: (details) {
_runAnimation();
},
Simulasi Gerakan Pegas
Pertama, impor paket Physics sebagai berikut:
import 'package:flutter/physics.dart';
Gunakan metode animateWith() dari AnimationController untuk membuat efek pegas seperti yang ditunjukkan di bawah ini:
void _runAnimation(Offset pixelsPerSecond, Size size) {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
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);
}
Terakhir, panggil fungsi _runAnimation() dengan velocity dan size sebagai parameter seperti yang ditunjukkan di bawah ini:
onPanEnd: (details) {
_runAnimation(details.velocity.pixelsPerSecond, size);
},
Berikut ini adalah source code lengkap setelah mengikuti langkah langkah di atas:
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
main() {
runApp(const MaterialApp(home: PhysicsCardDragDemo()));
}
class PhysicsCardDragDemo extends StatelessWidget {
const PhysicsCardDragDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Nextgen Tutorial'),
backgroundColor: Colors.blue,
),
body: const DraggableCard(
child: FlutterLogo(
size: 140,
),
),
);
}
}
class DraggableCard extends StatefulWidget {
final Widget child;
const DraggableCard({super.key, required this.child});
@override
State createState() => _DraggableCardState();
}
class _DraggableCardState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
Alignment _dragAlignment = Alignment.center;
late Animation _animation;
void _runAnimation(Offset pixelsPerSecond, Size size) {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
// evaluating velocity
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,
),
),
);
}
}
Output:
Tutorial sebelumnya : Animasi Dalam Transisi Route Di Flutter
Tutorial setelahnya : Lottie Animation Di Flutter
Semua Tutorial Flutter : Tutorial Flutter