اساسيات الـ Animation في Swift 3
قد تكون مبرمجاً بارعاً ومتمكناً ولكن تطبيقاتك لا تجذب المستخدمين ! .. لماذا ؟
بداية تذكر بأن هناك ألاف المطورين حول العالم ، فالمنافسة على اشدها !
هناك امرين مهمين، غير البرمجة وخلو او قلة المشاكل (Bugs) في تطبيقاتك
هما :
١. واجهة جميلة وجذابه (اذا كنت لست مصمماً ، تستطيع الاستعانة بمصممين واجهة المستخدم)
٢. تجربة المستخدم ، تجربة المستخدم جدا مهمه في كل شيء بما فيها التطبيقات (أيضا تستطيع الاستعانة بمصممين تجربة المستخدم)
بإختصار :
واجهة المستخدم UI : هي الواجهة التي تصممها ليتعامل معها المستخدم وهي ظاهرة له .
تجربة المستخدم UX : هي تجربة المستخدم مع تلك الواجهة ، اما أن تكون جيدة واما أن تكون سيئة .
فكما ذكرت سابقا كود نظيف وعملي + واجهة قبيحة + تجربة مستخدم سيئة = تطبيق سيئ !
يجب أي تتناسب جميع العناصر مع بعض لتجعل التطبيق مميز ومحبب لذا المستخدمين .
من الامور المفيدة في تحسين تجربة المستخدم هي الـ Animation
كمستخدم ايهما تفضل ؟
- عند كتابة كلمة السر بشكل خاطئ هل تفضل "رسالة كئيبة تفيد بأن كلمة السر التي ادخلتها خاطئة"
أم اهتزاز حقل كلمة السر تفيد بأن كلمة السر خاطئة ؟
- هل تفضل ظهور menu بدون تأثير وبشكل فجائي او بتأثير وبصورة سلسه ؟
- عند الحذف هل تفضل الحذف فجأة او بتأثير التلاشي مثلا ؟
بما سبق مجرد امثله بسيطة لكن لها تأثير في تجربة المستخدم للتطبيق ،
تم دمج الأمثلة لتعطي تصورا لأهمية الـ Animation ولكن يجب التوضيح بأن تجربة المستخدم أعمق من ذلك
وانصحك بالقراءة عنها.
أيضا يتوجب من الامور المهمة في تجربة المستخدم لا تبالغ بالـ Animation !
تذكر بأن أي أمر يزيد عن حده يصبح سيئا!
هناك نوعين من الـ Animation
Animation بدون Auto Layout
Animation مع Auto Layout
الـ Auto Layout هو باختصار جعل واجهة المستخدم تتوافق مع جميع احجام الشاشات .
معلومة : اغلب الـ Animation يعتمد على سطر واحد فقط !
UIView.animate(withDuration: (0.0) animations: {
})
withDuration :
تعني كم فترة التحريك بالثانية الواحده ؟
بداخل الاقواس تضع الاكواد التي تريدها تنفيذها
دعونا نبدأ في الشرح :
بداية نضيف زر ونضيف Auto Layout للزر
ثم نضع view ونغير لونه لأي لون تريده وأيضا نضيف الـ Auto Layout للـ View
من ثم نربط العناصر مع ملف الاكواد
الشكل النهائي :
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var squareView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func AnimationButton(_ sender: Any) {
}
}
تغير اللون :
في AnimationButton() نضيف هذا السطر :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.backgroundColor = UIColor.red
})
الظهور من العدم :
نضيف هذا السطر في Viewdidload
squareView.alpha = 0.0
و في AnimationButton() نضيف هذا السطر
UIView.animate(withDuration: (1.0) animations: {
squareView.alpha = 1.0
})
قبل العودة لباقي الأمثلة يتوجب عليك فهم امراً مهماً
وهو إحداثيات النظام المتبع في الاجهزة وبحكم موضوعنا عن لغة Swift
وتحديداً نظام iOS
فإحداثيات النظام هي :
قيمة x الموجب تكون في اليمين
وقيمة y الموجب تكون في الأسفل
صورة من موقع آبل :
صورة توضيحية :
معلومة الشروحات التالية لا تعتمد على الـ Auto Layout سيتم التطرق لطريقة أخرى في فقره قادمة
اقتباستذكر عند استخدام transform فان الـ view لن يهتم بالـ Auto Layout
التضخيم :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(scaleX: 2, y: 2)
})
كما تلاحظ من الكود السابق هناك قيمة x و y
قيمة أكس تضاعف من الجهتين x و –x
قيمة واي تضاعف من الجهتين العلوية والسفلية y و –y
جعل القيمتين متساوية تعني مضاعفة ابعاد المربع بالتساوي
وكيف يعمل ؟
يتم ضرب الطول في قيمة y
والعرض في قيمة x
التصغير :
اذا اردت التصغير فيتم استخدام نفس الكود السابق ولكن يتم إعطاء قيمة اصغر من 1
لأن 1 يساوي القيمة الاصلية
زيادته يساوي مضاعفه للحجم ، نقصانه يساوي تصغير الحجم
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8 ) })
التحريك بشكل عمودي :
الان سوف تفيدنا المعلومة السابقة المتعلقة بالإحداثيات
لأننا نريد تحريك المربع بشكل عمودي للأسفل فإننا نقوم بكتابة الأمر التالي :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(translationX:0, y: 400)
})
قيمة x بـ 0 لأننا لا نريد تحريك المربع بشكل افقي
قيمة y بـ 400 لأننا نريد تحريكه للأسفل بمقدار 400
التحريك بشكل أفقي :
الأن نريد تحريك المربع بشكل افقي الى اليسار
نقوم بكتابة الأمر التالي :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(translationX:-122, y: 0)
})
تم إعطاء قيمة x بـ -122 لأننا نريد تحريك المربع لليسار
اذا تم إعطاء قيمة موجبة سيتحرك المربع لليمين ، تذكر صورة الإحداثيات
وتم إعطاء قيمة y بـ 0 لأننا لا نريد تحريكه بشكل عمودي
ماذا اذا اعطينا قيمة لـ x وقيمة أخرى لـ y ؟
سوف يتحرك المربع بشكل مائل
لنجرب الكود التالي ونرى النتيجة :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(translationX:122, y: 300)
})
ماذا اذا اردنا التحريك بشكل حرف L ؟
هنا نحتاج الى تعلم معلومة جديدة ، وهيا :
ذكرنا في بداية الموضوع بأن هناك سطر واحد لتنفيذ الـ Animation
وفعلياً تسطيع تنفيذ جميع الامور السابقة مع بعض اذا تم اضافتها جميعها في داخل أقواس كود الـ Animation
ولكن
ماذا اذا اردنا تنفيذ Animation اخر بعد انتهاء الأول وليس في نفس الوقت ؟
هنا نحتاج استخدام كود مختلف
يمكنك ملاحظ الكود الذي تم اختياره في الـ Xcode في هذه الصورة :
من الصورة السابقة
الخيار المحدد هو الذي تم اختياره في هذه اللحظة
الخيار الذي قبله هو الذي كنا نستخدمه منذ بداية الموضوع
ومن ثم قمنا إضافة سطر Animation اخر بعد true
UIView.animate(withDuration: 1.0, animations: {
}) { (true) in
UIView.animate(withDuration: 1.0, animations: {
})
}
للتوضيح :
الامر الزائد هو وجود شرط وتم إعطائه قيمة true
يمكنك وضع أي شرط بحيث عن انتهاء الـ animation يحدث ما بداخل الشرط
ولكن لغرض تنفيذ الـ animation الاخر بعد انتهاء الاول مباشرة
لذا تم إعطاء قيمة true
وتم إضافة كود animation اخر بداخله
الان نعود لسؤالنا السابق
ماذا اذا اردنا التحريك بشكل حرف L ؟
نقوم بتنفيذ التالي :
UIView.animate(withDuration: 1.0, animations: {
self.squareView.transform = CGAffineTransform(translationX:0, y: 300)
}) { (true) in
UIView.animate(withDuration: 1.0, animations: {
self.squareView.transform = CGAffineTransform(translationX:-122, y: 300)
})
}
الذي قمنا به هو تحريك المربع بشكل عمودي في البداية بمقدار 300
وفي الكود التالي بداخل شرط الـ true
حافظنا على قيمة الـ y وحركنا قيمة الـ x باتجاه اليمين
الان نقو بحذف ما سبق ونعود لسطر الـ animation القديم
UIView.animate(withDuration: (1.0) animations: {
})
و قبل أن نستكمل الشرح ، حان الوقت لتعلم معلومة جديدة :
في الشرح القادم سوف نتعلم كيفية دوران/التفاف المربع
وبحكم الغالبية العظمى لا يتذكروا ما تم دراسته في مادة الرياضات
يتوجب عليا شرح بعض النقاط
لجعل المربع يلتف فإننا نعتمد على الزاوية
وبحكم اننا في الغالب سوف نحتاج الى دوران المربع بزاوية 90
او 180
فأننا سنحتاج تعلم هذه المعلومة
مجموع زوايا الدائرة هو 360 درجة والذي يساوي 2π
بما يعني اذا اردنا زاوية 180 فسوف تكون القيمة π
زاوية 180 تعني قلب المربع رأساً على عقب
واذا اردنا الزاوية 90 فسوف تكون القيمة π/2
زاوية 90 تعني الالتفاف الى الجهة اليمين
بما يعني زاوية -90 تعني الالتفاف الى الجهة اليسار
الان نعود للشرح
ماذا اذا اردنا التفاف المربع الى اليمين ؟
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2))
})
معلومية : Double.pi تعني π
ولأن CGAffineTransform ياخد قيمة من نوع CGFloat
فاننا نقوم بعملية casting الى CGFloat
ماذا يعني عملية الـ casting ؟
هي عملية تحويل من نوع معين الى نوع اخر
فنحن هنا نقوم بعملية تحويل من Double الى CGFloat
ماذا اذا اردنا التحريك بشكل عمودي والالتفاف في آنٍ واحد ؟
نقوم بكتابة الكود بهذا الشكل :
UIView.animate(withDuration: (1.0) animations: {
self.squareView.transform = CGAffineTransform(translationX:0, y: 300).rotated(by: CGFloat(Double.pi/2))
})
الان حان الوقت لنتعلم معلومة جديدة :
ماذا اذا اردنا تنفيذ كود التحريك بالعكس دون الحاجة الى كتابة الاكواد من جديد ؟
بما يعني عند الضغط على الزر مره اخرى فإنه يقوم بإعادة المربع الى موقع الاول !
كل ما علينا فعله هو الاستفادة من property في الـ CGAffineTransform
تدعى identity
تمت اضافتها في iOS10
وظيفتها تقوم بحفظ الاحداتياث قبل تنفيذ الـ animations
الان لكيفية الاستخدام
نقوم بكتابة الاكود بالشكل التالي:
UIView.animate(withDuration: 1.0) {
if self.squareView.transform == CGAffineTransform.identity{
self.squareView.transform = CGAffineTransform(translationX:0, y: 300).rotated(by: CGFloat(Double.pi/2))
}else {
self.squareView.transform = CGAffineTransform.identity
}
}
الـ if وظيفتها تحفظ الموقع قبل عمل الـ animations
وفي الـ else نقوم بكتابة نفس السطر بدون الـ if
لعمل الـ animation بشكل عكسي
وبالتالي بسطر واحد تقوم على تنفيذ الكود الـ animations بشكل عكسي .
عمل animations مع الـ Auto Layout
اقتباسالجزئية القادمة تعتمد على معرفتك للـ Auto Layout
اذا كنت لا تعلم ما هو Auto Layout وكيفية استخدامه
يتوجب عليك تعلمه قبل استكمال الشرح
لنبدا الشرح :
بداية يتوجب عليك إضافة الـ LayoutConstraint
نحن نحتاج الى الـ Top وهو المسؤول عن التحريك بشكل عمودي
وأيضا نحتاج الى الـ Leading وهو المسؤول عن التحريك بشكل افقي
لمعرفة كيفية اضافتهم الى ملف الاكواد ، شاهد الصورة المتحركة التالية :
تحريك المربع بشكل عمودي :
لاحظ القيود التي وضعناها في بداية الموضوع
وضعنا القيود من الأعلى ومن يمين ومن اليسار فقط !
لم نوضع قيود في الأسفل
لذا لتحريك المربع الى الأسفل نقوم بكتابة السطر التالي
UIView.animate(withDuration: (1.0) animations: {
self.top.constant = 400
self.view.layoutIfNeeded()
})
الذي قمنا به هنا هو تغير قيمة الـ top
ومن ثم اضفنا هذا السطر
self.view.layoutIfNeeded()
السطر هذا وظيفته تحديث الـ Auto Layout
بشكل متدرج
بدون اضافته في النهاية الكود
سوف يسبب في تغير موقع المربع بشكل فجائي
تحريك المربع بشكل افقي :
الان لأننا نريد تحريك المربع بشكل افقي يتوجب علينا تعديل القيود أولا
غير القيود الى الشكل التالي :
ومن ثم قم بكتابة الكود التالي :
UIView.animate(withDuration: (1.0) animations: {
self.Leading.constant = 240
self.view.layoutIfNeeded()
})
ماذا اذا اردنا تصغير المربع ؟
نحتاج أولا تغيير القيود الى هذا الشكل :
ومن ثم إضافة الـ LayoutConstraint
الخاص بـ Trailing
ومن ثم كتابة هذه الأسطر :
UIView.animate(withDuration: (1.0) animations: {
self.Leading.constant = 150
self.Trailing.constant = 150
self.view.layoutIfNeeded()
})
الذي قمنا به هو تغير القيود من الجانب الأيمن والايسر وبالتالي يتم تصغير المربع مع المحافظة على موقعه
لذلك لم نغير قيمة الـ top
تلميحه اخيره !
كيفية معرفة الموقع النهائي للمربع ؟
بمعنى عندما اريد تحريك المربع بشكل عمودي
كيف معرفة كم سوف يتوجب عليا جعل قيمة الـ top في حالة التحريك باستخدام الـ Auto Layout ؟
الطريقة تعتمد على الـ Storyboard
- نرى كم قيمة الـ top قبل التحريك
- نقوم بتحريك المربع
- سيظهر لنا لون برتقالي يوضح مقدار التغير الذي حدث
- نضيف القيمة التي نراها مع القيمة السابقة
قبل التحريك قيمة الـ top كانت 92
وعندما قمنا بالتحريك ظهرت قيمة +261
اذا نقوم بجميع قيمة 92 + 261 = 353
وبتالي قيمة الـ top تصبح 353
الطريقة الثانية اننا نعتمد على قيمة الـ y
كما في المثال القادم
في حالة اردنا التحريك بدون استخدام الـ Auto Layout
فإننا نعتمد على قيمة y
كما في الصورة التالية :
التعليقات (0)
عرض المزيد.. جديد مقالاتي
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !