اساسيات الـ Animation في Swift 3

باسل بارقبهمنذ 6 سنوات

قد تكون مبرمجاً بارعاً ومتمكناً ولكن تطبيقاتك لا تجذب المستخدمين ! .. لماذا ؟
بداية تذكر بأن هناك ألاف المطورين حول العالم ، فالمنافسة على اشدها !

 

هناك امرين مهمين، غير البرمجة وخلو او قلة المشاكل (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 للزر

1.thumb.png.e84c65912376ff4073b0904e0120eb34.png

ثم نضع view ونغير لونه لأي لون تريده وأيضا نضيف الـ Auto Layout للـ View


2.thumb.png.a9234e5da1c4e3c202769a1cf47529f6.png

من ثم نربط العناصر مع ملف الاكواد

 

الشكل النهائي :


import UIKit



class ViewController: UIViewController {



    

    @IBOutlet weak var squareView: UIView!

    

    override func viewDidLoad() {

        super.viewDidLoad()     

    }



    @IBAction func AnimationButton(_ sender: Any) {

         

    }

            

}

 

تغير اللون :

3.gif.bec8b12ecb688001e7f482f3d056cd22.gif

 

في AnimationButton()  نضيف هذا السطر :
 


UIView.animate(withDuration: (1.0) animations: {



self.squareView.backgroundColor = UIColor.red



})

 

الظهور من العدم :


4.gif.7209c5ba1706a69c9e9052554dc7cd03.gif
 

نضيف هذا السطر في Viewdidload
 


squareView.alpha = 0.0

 

و في AnimationButton() نضيف هذا السطر
 


UIView.animate(withDuration: (1.0) animations: {



squareView.alpha = 1.0



})


قبل العودة لباقي الأمثلة يتوجب عليك فهم امراً مهماً

وهو إحداثيات النظام المتبع في الاجهزة وبحكم موضوعنا عن لغة Swift

 وتحديداً نظام iOS

فإحداثيات النظام هي :

قيمة x الموجب تكون في اليمين
وقيمة y الموجب تكون في الأسفل

 

صورة من موقع آبل  :

5.jpg.89e8bb19a491ac3d8cad41ac4cc7fb4b.jpg

 

 صورة توضيحية :

6.thumb.png.6cb806d45c908d143fa182aa8311387a.png


معلومة الشروحات التالية لا تعتمد على الـ Auto Layout سيتم التطرق لطريقة أخرى في فقره قادمة

 

اقتباس

تذكر عند استخدام transform فان الـ view لن يهتم بالـ Auto Layout

 
 


التضخيم :

7.gif.bdb16b0d80fe9dac479da69ab2658a33.gif

 


UIView.animate(withDuration: (1.0) animations: {



               self.squareView.transform = CGAffineTransform(scaleX: 2, y: 2)



})


كما تلاحظ من الكود السابق هناك قيمة x و y

قيمة أكس تضاعف من الجهتين x و –x
قيمة واي تضاعف من الجهتين العلوية والسفلية y و –y

جعل القيمتين متساوية تعني مضاعفة ابعاد المربع بالتساوي

 

وكيف يعمل ؟

يتم ضرب الطول في قيمة y

والعرض في قيمة x

 

التصغير :

8.gif.2b3f397eeac8543de6ee9e38ea403607.gif
 

اذا اردت التصغير فيتم استخدام نفس الكود السابق ولكن يتم إعطاء قيمة اصغر من 1

لأن 1 يساوي القيمة الاصلية

زيادته يساوي مضاعفه للحجم ، نقصانه يساوي تصغير الحجم


UIView.animate(withDuration: (1.0) animations: {



               self.squareView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8 ) })


التحريك بشكل عمودي :
 

9.gif.8ace29ac54a124dcb73a3e7e28af6848.gif


الان سوف تفيدنا المعلومة السابقة المتعلقة بالإحداثيات

لأننا نريد تحريك المربع بشكل عمودي للأسفل فإننا نقوم بكتابة الأمر التالي :


UIView.animate(withDuration: (1.0) animations: {



              self.squareView.transform = CGAffineTransform(translationX:0, y: 400)



})

 

قيمة x بـ 0 لأننا لا نريد تحريك المربع بشكل افقي

قيمة y بـ 400 لأننا نريد تحريكه للأسفل بمقدار 400

 

التحريك بشكل أفقي :
 

10.gif.6f6965d8e08b4f295c3264dfa5d22749.gif


الأن نريد تحريك المربع بشكل افقي الى اليسار

نقوم بكتابة الأمر التالي :


UIView.animate(withDuration: (1.0) animations: {



                self.squareView.transform = CGAffineTransform(translationX:-122, y: 0)

})


 

تم إعطاء قيمة x بـ -122 لأننا نريد تحريك المربع لليسار

اذا تم إعطاء قيمة موجبة سيتحرك المربع لليمين ، تذكر صورة الإحداثيات

وتم إعطاء قيمة y بـ 0 لأننا لا نريد تحريكه بشكل عمودي

 

ماذا اذا اعطينا قيمة لـ x وقيمة أخرى لـ y ؟

سوف يتحرك المربع بشكل مائل


11.gif.9bcc36e352372a5bf9718e8fd4bc22fe.gif
 

لنجرب الكود التالي ونرى النتيجة :


UIView.animate(withDuration: (1.0) animations: {



                self.squareView.transform = CGAffineTransform(translationX:122, y: 300)



})

 

ماذا اذا اردنا التحريك بشكل حرف L ؟

 

هنا نحتاج الى تعلم معلومة جديدة ، وهيا :

ذكرنا في بداية الموضوع بأن هناك سطر واحد لتنفيذ الـ Animation

وفعلياً تسطيع تنفيذ جميع الامور السابقة مع بعض اذا تم اضافتها جميعها في داخل أقواس كود الـ Animation

 

 ولكن

ماذا اذا اردنا تنفيذ Animation اخر بعد انتهاء الأول وليس في نفس الوقت ؟

 

هنا نحتاج استخدام كود مختلف

يمكنك ملاحظ الكود الذي تم اختياره في الـ Xcode في هذه الصورة :

12.thumb.png.43e4847e46b280adce0bef06b89f6578.png
 

من الصورة السابقة

الخيار المحدد هو الذي تم اختياره في هذه اللحظة

الخيار الذي قبله هو الذي كنا نستخدمه منذ بداية الموضوع

ومن ثم قمنا إضافة سطر Animation اخر بعد true


UIView.animate(withDuration: 1.0, animations: {

    

}) { (true) in

    

    UIView.animate(withDuration: 1.0, animations: {

        

    })

    
        }

 

للتوضيح :

الامر الزائد هو وجود شرط وتم إعطائه قيمة true

يمكنك وضع أي شرط بحيث عن انتهاء الـ animation يحدث ما بداخل الشرط

ولكن لغرض تنفيذ الـ animation الاخر بعد انتهاء الاول مباشرة

لذا تم إعطاء قيمة true

وتم إضافة كود animation  اخر بداخله

 

الان نعود لسؤالنا السابق

ماذا اذا اردنا التحريك بشكل حرف L ؟



13.gif.211ba99b13a2276a9b4cb6f5a2ed72df.gif


نقوم بتنفيذ التالي :


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 درجة والذي يساوي

 

بما يعني اذا اردنا زاوية 180 فسوف تكون القيمة π

زاوية 180  تعني قلب المربع رأساً على عقب

 

واذا اردنا الزاوية 90 فسوف تكون القيمة π/2

زاوية 90 تعني الالتفاف الى الجهة اليمين

 

بما يعني زاوية -90 تعني الالتفاف الى الجهة اليسار

 

الان نعود للشرح

 

ماذا اذا اردنا التفاف المربع الى اليمين ؟


14.gif.d19b0621fa57ec474f378e1dc2574b4b.gif
 


UIView.animate(withDuration: (1.0) animations: {



self.squareView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2))



})

 

معلومية : Double.pi تعني π

ولأن CGAffineTransform ياخد قيمة من نوع CGFloat

فاننا نقوم بعملية casting الى CGFloat

 

ماذا يعني عملية الـ casting ؟

هي عملية تحويل من نوع معين الى نوع اخر

فنحن هنا نقوم بعملية تحويل من Double الى CGFloat

 

ماذا اذا اردنا التحريك بشكل عمودي والالتفاف في آنٍ واحد ؟


15.gif.eaa839f1c581a5fc652a889be6afb651.gif


نقوم بكتابة الكود بهذا الشكل :


UIView.animate(withDuration: (1.0) animations: {



                  self.squareView.transform = CGAffineTransform(translationX:0, y: 300).rotated(by: CGFloat(Double.pi/2))



})


الان حان الوقت لنتعلم معلومة جديدة :

ماذا اذا اردنا تنفيذ كود التحريك بالعكس دون الحاجة الى كتابة الاكواد من جديد ؟


16.gif.06d036f4757d2331d77475f756502224.gif
 

بما يعني عند الضغط على الزر مره اخرى فإنه يقوم بإعادة المربع الى موقع الاول !

كل ما علينا فعله هو الاستفادة من 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 وهو المسؤول عن التحريك بشكل افقي

 

لمعرفة كيفية اضافتهم الى ملف الاكواد ، شاهد الصورة المتحركة التالية :


17.thumb.gif.ac4f8ffc12c0fa97058c321d524c2428.gif


تحريك المربع بشكل عمودي :

18.gif.8b2a835798ecd0281cc81972876dcff6.gif
 

لاحظ القيود التي وضعناها في بداية الموضوع

وضعنا القيود من الأعلى ومن يمين ومن اليسار فقط !

لم نوضع قيود في الأسفل

 

لذا لتحريك المربع الى الأسفل نقوم بكتابة السطر التالي


UIView.animate(withDuration: (1.0) animations: {



      self.top.constant = 400

self.view.layoutIfNeeded()



})

 

الذي قمنا به هنا هو تغير قيمة الـ top

ومن ثم اضفنا هذا السطر


self.view.layoutIfNeeded()

السطر هذا وظيفته تحديث الـ Auto Layout

بشكل متدرج

بدون اضافته في النهاية الكود

سوف يسبب في تغير موقع المربع بشكل فجائي

 

تحريك المربع بشكل افقي :


20.gif.60accf84bede555d46209186bbebe942.gif



الان لأننا نريد تحريك المربع بشكل افقي يتوجب علينا تعديل القيود أولا

غير القيود الى الشكل التالي :
 

19.thumb.png.4474205dba488530679377b75a1d6ef3.png

 

ومن ثم قم بكتابة الكود التالي :


UIView.animate(withDuration: (1.0) animations: {



      self.Leading.constant = 240

self.view.layoutIfNeeded()



})

 

ماذا اذا اردنا تصغير المربع ؟


25.gif.de9c6cb1f3f35a88ad748354f6d0c06a.gif
 

نحتاج أولا تغيير القيود الى هذا الشكل :


21.thumb.png.7917272d8ec2c276fb9701ab81e9ab99.png

 

ومن ثم إضافة الـ LayoutConstraint
الخاص بـ Trailing

كما في الصورة التالية :

22.thumb.png.5dd5456b40dcdfbebd1d55e13ee26ccc.png

 

ومن ثم كتابة هذه الأسطر :


UIView.animate(withDuration: (1.0) animations: {



 self.Leading.constant = 150

              

self.Trailing.constant = 150



self.view.layoutIfNeeded()





})

 

الذي قمنا به هو تغير القيود من الجانب الأيمن والايسر وبالتالي يتم تصغير المربع مع المحافظة على موقعه

لذلك لم نغير قيمة الـ top

 

تلميحه اخيره !

كيفية معرفة الموقع النهائي للمربع ؟

بمعنى عندما اريد تحريك المربع بشكل عمودي

كيف معرفة كم سوف يتوجب عليا جعل قيمة الـ top في حالة التحريك باستخدام الـ Auto Layout ؟

 

الطريقة تعتمد على الـ Storyboard

-       نرى كم قيمة الـ top قبل التحريك

-       نقوم بتحريك المربع

      سيظهر لنا لون برتقالي يوضح مقدار التغير الذي حدث

      نضيف القيمة التي نراها مع القيمة السابقة

 

في هذه الصورة المتحركة :

23.thumb.gif.f9d3759c7caf9c9529988d9c702a083c.gif



قبل التحريك قيمة الـ top كانت 92
وعندما قمنا بالتحريك ظهرت قيمة +261

اذا نقوم بجميع قيمة 92 + 261 = 353

وبتالي قيمة الـ top تصبح 353

 

الطريقة الثانية اننا نعتمد على قيمة الـ y

كما في المثال القادم

 

في حالة اردنا التحريك بدون استخدام الـ Auto Layout

فإننا نعتمد على قيمة y

كما في الصورة التالية :

24.thumb.gif.e008d09956f348e8e4b0e04a6dfe09c8.gif

 

كلمات دليلية:
2
إعجاب
3034
مشاهدات
0
مشاركة
0
متابع
متميز
محتوى رهيب

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !