في عالم تطوير التطبيقات باستخدام Flutter، أصبحت الرسوم المتحركة القائمة على الفيزياء أداة أساسية لإضافة لمسة واقعية وتفاعلية إلى الواجهات.
تخيّل أنك تقوم بسحب بطاقة على الشاشة، ثم تتركها لتعود إلى مكانها الأصلي بحركة زنبركية طبيعية! هذا بالضبط ما تمنحه لنا الرسوم الفيزيائية: محاكاة حقيقية لقوانين الطبيعة مثل السرعة، القوة، والاحتكاك.
في هذا المقال، سنستعرض خطوة بخطوة كيفية تنفيذ مثل هذه الرسوم في Flutter، بالاعتماد على دليل Flutter الرسمي (Cookbook). سواء كنت مطورًا مبتدئًا أو محترفًا، ستجد هنا أمثلة كود عملية ونصائح لتحقيق أفضل النتائج، مع التركيز على تحسين الأداء وتجربة المستخدم.
ما هي الرسوم المتحركة القائمة على الفيزياء؟
ببساطة:
- الرسوم التقليدية في Flutter (Tween Animations) تعتمد على الانتقال من قيمة إلى أخرى خلال فترة زمنية.
- أما الرسوم الفيزيائية (Physics-based animations) فهي تحاكي الحركة الطبيعية مثل الزنبرك أو الجاذبية.
في Flutter، يمكننا استخدام مكتبة:
import 'package:flutter/physics.dart';
لإنشاء محاكاة فيزيائية تجعل العناصر تستجيب لإيماءات المستخدم بطريقة طبيعية ومقنعة.
لماذا نحتاجها؟
- تضيف إحساسًا بالحيوية للتطبيق.
- تجعل التفاعل يبدو وكأنه يحدث في العالم الحقيقي.
- مثال: عند سحب بطاقة وإفلاتها، تعود بحركة سلسة تشبه حركة نابض، مما يقلل من الإحساس بالجمود أو “الآلية”.
خطوات التنفيذ
سنقسم التنفيذ إلى أربع مراحل، مع أمثلة كود عملية:
1. إعداد متحكم الرسوم المتحركة (AnimationController)
أول خطوة: إنشاء StatefulWidget مع متحكم AnimationController.
import 'package:flutter/material.dart';
void 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 {
const DraggableCard({required this.child, super.key});
final Widget child;
@override
State<DraggableCard> createState() => _DraggableCardState();
}
class _DraggableCardState extends State<DraggableCard> with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Align(child: Card(child: widget.child));
}
}
2. إضافة إيماءات السحب (Gestures)
الآن نريد أن يتغير موضع البطاقة عند السحب:
class _DraggableCardState extends State<DraggableCard> with SingleTickerProviderStateMixin {
late AnimationController _controller;
Alignment _dragAlignment = Alignment.center;
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return GestureDetector(
onPanUpdate: (details) {
setState(() {
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
});
},
child: Align(
alignment: _dragAlignment,
child: Card(child: widget.child),
),
);
}
}
الآن يمكن سحب البطاقة في أي مكان.
3. إرجاع البطاقة إلى المركز (Animation with Tween)
بعد إفلات البطاقة، نريدها أن تعود لمركز الشاشة:
void _runAnimation() {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
_controller.reset();
_controller.forward();
}
ثم نربطها بـ onPanEnd:
onPanEnd: (details) {
_runAnimation();
},
4. استخدام محاكاة زنبركية (Spring Simulation)
الآن الجزء الممتع! نستبدل الحركة الخطية بمحاكاة زنبركية طبيعية:
import 'package:flutter/physics.dart';
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 unitVelocity = Offset(unitsPerSecondX, unitsPerSecondY).distance;
const spring = SpringDescription(mass: 30, stiffness: 1, damping: 1);
final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
_controller.animateWith(simulation);
}
وهكذا، تصبح الحركة طبيعية: البطاقة تعود للمركز وكأنها مربوطة بزنبرك!
نصائح لتحسين الأداء
- استخدم
vsyncلتوفير الطاقة. - جرّب معاملات مختلفة لـ
SpringDescriptionللحصول على حركة أنسب. - اختبر على أجهزة متنوعة لضمان سلاسة التجربة.
- يمكنك الدمج مع Hero Animations لانتقالات أكثر واقعية بين الشاشات.
الخاتمة
الرسوم الفيزيائية في Flutter قادرة على تحويل واجهات تطبيقاتك إلى تجربة تفاعلية واقعية.
من خلال استخدام AnimationController و SpringSimulation، يمكنك بناء حركات تشعر المستخدم وكأنها تحدث في العالم الحقيقي.
جرب الكود بنفسك، وستلاحظ الفرق الكبير في تفاعل المستخدم مع تطبيقك.

