אנימציות מחוות אינטראקטיביות לאפליקציות מובייל
אנחנו בונים אנימציות מחוות שלא מגמגמות ולא מרגישות זולות. לצוות שלנו יש ניסיון של 5+ שנים בפיתוח מובייל ומעל 20 פרויקטים עם אנימציות מותאמות אישית. ההבדל בין אנימציות מחוות לאנימציות רגילות הוא שאנימציות מחוות ניתנות להפרעה. משתמש גורר כרטיס, משנה את דעתו באמצע הדרך, והוא חייב לחזור עם התנהגות פיזית מדויקת—לא רק לקפוץ חזרה, אלא לקפוץ עם מהירות מצטברת. זו אנימציית מחוות אינטראקטיבית—אנימציה שמונעת על ידי האצבע בזמן אמת.
אם אתם לא בטוחים לגבי לוחות זמנים, צרו קשר—נעריך את ההיקף והעלות.
למה סנכרון מהירות הוא האתגר המרכזי
הפרמטר המרכזי של כל אנימציית מחוות הוא החיבור בין מהירות המחווה בשחרור (gestureRecognizer.velocity) לפרמטרים הסופיים של האנימציה. אם הם לא מסונכרנים, מקבלים "קפיצה": האצבע נעה במהירות אחת, אבל האובייקט מסיים במהירות אחרת.
ב-iOS, UIViewPropertyAnimator מטפל בזה באופן טבעי דרך continueAnimation(withTimingParameters:durationFactor:):
@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: view)
switch gesture.state {
case .changed:
animator?.fractionComplete = translation.y / totalDistance
case .ended:
let velocity = gesture.velocity(in: view)
let springVelocity = abs(velocity.y) / (totalDistance - translation.y)
let timing = UISpringTimingParameters(dampingRatio: 0.8, initialVelocity: CGVector(dx: 0, dy: springVelocity))
animator?.continueAnimation(withTimingParameters: timing, durationFactor: 0)
default:
break
}
}@objc func handlePan(_ gesture: UIPanGestureRecognizer) { let translation = gesture.translation(in: view) switch gesture.state { case .changed: animator?.fractionComplete = translation.y / totalDistance case .ended: let velocity = gesture.velocity(in: view) let springVelocity = abs(velocity.y) / (totalDistance - translation.y) let timing = UISpringTimingParameters(dampingRatio: 0.8, initialVelocity: CGVector(dx: 0, dy: springVelocity)) animator?.continueAnimation(withTimingParameters: timing, durationFactor: 0) default: break } } ממפה ישירות את התקדמות האנימציה לקלט המחווה. ערך של 0.0 הוא התחלה, 1.0 הוא סוף. המשתמש ממש גורר את האנימציה לאורכה. להבנה מעמיקה יותר, ראו תיעוד UIKit.
איך ליישם כרטיסי החלקה-לסגירה
התבנית הקלאסית של Tinder או רשימת משימות: הכרטיס עוקב אחרי האצבע, בסף מסוים הוא עף משם, מתחת לסף הוא חוזר.
שלושה פרמטרים לכיול:
- סף שחרור—בדרך כלל 30-40% מרוחב המסך או מהירות > 800 pt/s
- זווית סיבוב—
fractionCompleteיוצר תחושה פיזית - מהירות אנימציית הסגירה—חייבת להתאים למהירות המחווה, אחרת הכרטיס "נתלה" באוויר
באנדרואיד, אנחנו משתמשים ב-transform = CGAffineTransform(rotationAngle: translation.x / screenWidth * 0.3) או ViewDragHelper עבור RecyclerView. ItemTouchHelper טוב לרשימות אבל מוגבל—ציור משוב מותאם אישית דורש דריסה של ItemTouchHelper. ב-Flutter, onChildDraw למקרים פשוטים, Dismissible + GestureDetector עם AnimationController למקרים מורכבים. fling() מקבל ישירות fling() מ-velocity—בדיוק הסנכרון שהסברנו.
השוואת פלטפורמות
| פרמטר | iOS | אנדרואיד | Flutter |
|---|---|---|---|
| סנכרון מהירות | DragEndDetails.velocity.pixelsPerSecond |
UIViewPropertyAnimator.continueAnimation + ViewDragHelper |
VelocityTracker |
| החלקת כרטיס | fling(velocity) + fractionComplete |
UISpringTimingParameters + ItemTouchHelper |
RecyclerView + Dismissible |
| רענון-במשיכה מותאם אישית | ScrollView offset + Lottie | DragTarget מותאם אישית + Lottie |
SwipeRefreshLayout + RefreshIndicator |
רענון-במשיכה עם אנימציה מותאמת אישית
AnimationController ו-UIRefreshControl הסטנדרטיים לא תומכים באנימציות אינדיקטור מותאמות אישית. אנחנו מיישמים דרך SwipeRefreshLayout עם אופסט שלילי: כאשר ScrollView, אנחנו מניעים אינדיקטור מותאם אישית עם התקדמות = contentOffset.y < -threshold. אנימציית Lottie, מקושרת ל-abs(offset.y) / threshold, נותנת עיצוב חופשי. השתמשו ב-setProgress() ב-iOS ו-LottieAnimationView.setProgress() באנדרואיד כדי לקשר במדויק את התקדמות האנימציה לאופסט.
גרירה ושחרור עם התנהגות פיזית
ב-iOS—LottieDrawable.setProgress() + UIDragInteraction עבור DnD בין אפליקציות, UIDropInteraction + UILongPressGestureRecognizer בתוך האפליקציה. חשוב: בהרמת פריט, הוסיפו אנימציית קנה מידה (1.05) וצל—משוב ויזואלי "אני מחזיק את האובייקט". בחזרה—UIViewPropertyAnimator עם dampingRatio גבוה (0.9) ל"נחיתה רכה".
בדיקות וכיול
- הפעילו אנימציות איטיות בסימולטור לניפוי ויזואלי.
- הריצו Xcode Instruments—Animation Hitches על מכשיר פיזי, שמרו על זמן פריים GPU מתחת ל-16ms (60fps).
- בדקו את כל המצבים: החזקה, החלקה מהירה, נגיעה חוזרת במהלך האנימציה.
- ודאו שפרמטרי האנימציה (damping, stiffness) תואמים לעיצוב.
הערה
השתמשו ב-Xcode Instruments וב-Profile GPU Rendering באנדרואיד לניפוי מעמיק.אנימציות מחוות חייבות להיבדק על מכשירים פיזיים—אמולטורים לא משחזרים פיזיקת מגע מדויקת. אנימציות איטיות בסימולטור עוזרות לתפוס פגמים, אבל התחושה האמיתית היא רק על חומרה. באנדרואיד, בדקו את זמן פריים GPU דרך Profile GPU Rendering. למבני release, ודאו ש-ProGuard לא מסיר מחלקות Lottie: הוסיפו UISpringTimingParameters.
כדי לכייל אנימציות לעיצוב שלכם, צרו קשר—נתחשב בכל הניואנסים.
מה כלול
- פיתוח אב טיפוס אנימציה עם כיול פרמטרים
- אינטגרציה עם העיצוב שלכם (Lottie, Rive, או Core Animation)
- בדיקות על 5+ מכשירים פיזיים
- מסירת קוד מקור מתועד
- תמיכה למשך שבועיים לאחר השחרור
לוח זמנים טיפוסי: 2–3 ימים לכל תבנית אנימציית מחוות, כולל אינטגרציה וכיול. העלות נקבעת לאחר ניתוח הדרישות הספציפיות שלכם. אנחנו מבטיחים 60fps חלקים על כל המכשירים. קבלו ייעוץ לפרויקט שלכם—צרו קשר להערכה.







