أساسيات الـ Animation في Swift 3 الجزء الخامس

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

في هذا الجزء سوف ننتقل الي نوع اخر مختلف عنما اعتدنا عليه سابقا

 

سوف ننتقل من Animation الـ View الى Animation الـ Layer

 

بصيغة أخرى هذا الموضوع هو بداية الدخول  الى الـ Core Animation

 

هناك فروقات كثيره بينهم !

 

ابرزها :

  • كل امر فعلته باستخدام الـ UIView Animation تستطيع عمله باستخدام الـ Layer Animation ولا يمكن فعل العكس

لماذا ؟

لانه الـ Layer يكون خلف الـ View
وبتالي عند تحريك الـ View مثلا انت أيضا تحرك الـ Layer

بما يعني أي امر تستطيع عمله بالـ View أيضا تستطيع عمله بالـ Layer
لانه طبقة الـ layer موجودة خلف الـ View

ولكن لا يمكن عمل العكس .
 

  • ملكيات الـ Layer التي يمكنك عمل لها  Animation  أكثر بكثير من ملكيات الـ UIView ، بمعنى اخر تستطيع فعل الكثير باستخدام Layer Animation
  • الـ Layer Animation ينفذ باستخدام المعالج الرسومي GPU في حين الـ UIView باستخدام المعالج المركزي CPU
  • الـ Layer Animation يمكن عمل Animation بشكل 3D و  2D في حين UIView Animation ، يمكن عمل Animation بشكل 2D فقط
  • الـ UIView Animation اسهل استخداما من الـ Layer Animation
  • يمكن دمج الـ Layer Animation مع الـ UIView Animation

 

مختصر الكلام الـ UIView Animation هو نسخه مخففه من الـ Layer Animation


بعد معرفة الفروقات لنبدأ الدرس :

 

لأثبات كلامي السابق

 

سوف نحاول عمل Animation يقوم بتحويل المربع الى دائرة باستخدام UIView Animation



بكتابة الكود التالي :

 


 @IBAction func AnimationButton(_ sender: Any) {

        

        UIView.animate(withDuration: 0.3) { 

          

            self.squareView.layer.cornerRadius = 61

        }

        

    }

 

ما فعلته هنا هو غيرت زوايا المربع من 0 الى 61
لماذا 61 ؟

لانه الطول والعرض للمربع هو 122 ، وبالتالي لتحويل المربع الى دائره نجعل زواية المربع تساوي
أضلاع المربع قسمة 2

بما يعني 122 قسمة 2 = 61

 

الان نرى النتيجة في الصورة التالية :

 

596572ee1ea10_Jul-03-201701-13-44.gif.822e64396a2bbba6f6d20c7feffc24e2.gif

 

كما ترى لم يتم حدوث Animation

ولكن فقط تم تحويل المربع الى دائره بشكل فجائي

 

والسبب كما ذكرنا سابقا

 

 لا يمكنه عملAnimation للـ Layer باستخدام UIView Animationالـ
 

اذا ماهو الـ Layer Animation الذي سوف نتحدث عنه اليوم ؟

 

كما الامر في UIView Animation

هناك أنواع مختلفة

 

أيضا في الـ Layer Animation

هناك أنواع مختلفة

 

النوع الذي سوف نتحدث عنه اليوم هو CABasicAnimation

 

سوف نعود الى المربع الأزرق الذي استخدمناه في المواضيع السابقة

 

لذا قم بإضافة "زر" وقم بربطه بملف الاكواد كـ Action
باسم AnimationButton

وقم بإضافة UIView واعطيه لوناً

 

وقم بربطه بملف الاكواد باسم squareView

 

الان سوف نبدأ في شرح الـ  Layer Animation

 

كيف يتم كتابة كود الـ Layer Animation؟

 

الطريقة مختلفة عن الـ UIView Animation

 

فهيا تعتمد أولا على تعريف خصائص الـ Animation

وفي الأخير في سطر واحد يتم تنفيذ الـ Animation

 

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


@IBAction func AnimationButton(_ sender: Any) {



   let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius")

cornerRadiusAnimation.duration = 0.3



        cornerRadiusAnimation.fromValue = 0

        

        cornerRadiusAnimation.toValue = 61



        

   squareView.layer.add(cornerRadiusAnimation, forKey: nil)

}

 

في المثال السابق :

 

اول سطر قمنا بتعريف متغير cornerRadiusAnimation

من نوع  CABasicAnimation

 

 

لاحظ الـ keypath

تقوم بالكتابة فيه نوع الـ Animation الذي تريد عمله

 

هنا نحن نريد عمل Animation للزوايا او بصيغة أخرى الـ cornerRadius

 

من ثم قمنا بكتابة الـ duration

الوقت المراد عمل في الـ Animation
بالثانية (مدة الـ Animation)

 

ومن ثم نحدد القيمة الاولية و القيمة النهائية

 

بما يعني في اول قيمة fromValue

نحدد القيمة الحالية

قمنا بكتابة 0

لأننا نعلم بأنه القيمة الاولية هيا 0 وبالتالي يظهر الشكل بشكل مربع !

 

toValue

هيا القيمة التي نريد الوصول اليها

نحن نريد ان تكون قيمة الـ cornerRadius

تساوي 61 وبالتالي يتغير الشكل من مربع الى دائره

 

الان انتهينا من وضع الخصائص الخاصة بالـ Animation

 

يبقى التنفيذ

 

في اخر سطر نفذنا الـ Animation

عن طريق استخدام add


   squareView.layer.add(cornerRadiusAnimation, forKey: nil)

 

الان قم بتشغيل الكود

وسوف تلاحظ الـ Animation

عند تغيره من مربع الى دائره

 

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

59657320090e9_Jul-03-201701-18-48.gif.b47c17d5ce5957e2065a61cc11735491.gif

 

لكن هناك مشكلة !!

عند الانتهاء من الـ Animation تم إعادة الـ View
الى الشكل المربع ولم يبقى على شكل الدائره

لماذا ؟؟

 

لتوضيح المشكلة بأبسط صورة ممكنه

عند عمل الـ Animation
الـ Core Animation ينفذها عن طريق استخدام الـ layer.add

وعندما ينتهي الـ Animation يقوم بحذفها

بما يعني لا يحدث تغير في القيمة الفعلية للـ Layer

فيظل الـ View كما كان بدون تغير !

 

لحل المشكلة

هناك حلين ، وكلاهما صحيحان

 

الاول :

 

نقوم بتغير الـ View الى الوضع الذي نريده عندما ينتهي الـ Animation

 

نحن نريد جعل الحواف بقيمة 61

وذلك لتحويله الى دائرة

 

لذا نقوم بكتابة السطر التالي


 


squareView.layer.cornerRadius = 61

 

بعد السطر

 


squareView.layer.add(cornerRadiusAnimation, forKey: nil)

 

وبالتالي تحل المشكلة !

 

 

الحل الثاني :

 

نقوم بإضافة السطرين التالين :


animation.isRemovedOnCompletion = false

animation.fillMode = kCAFillModeForwards

 

ضعهم في أي مكان قبل


squareView.layer.add

 

وستجده أيضا يعمل !

لكن هذا الحل غير مفضل دائماً !

 

لماذا ؟

 

عندما يحدث الـ Animation في الـ Core Animation

انت في الحقيقة لا تشاهد الـ Layer يحدث له الـ Animation

ولكن الذي تشاهده هو نسخه طبق الأصل منه ، بما يعني الـ Cache الخاص بالـ Layer

هو الذي يحدث له Animation

ويطلق عليه اسم Presentation Layer

 

وعندما تستخدم الاسطر الماضية فالذي تقوم به هو حفظ الـ Presentation Layer

وتمنع ازالته من الشاشة

هذا الامر يسبب مشكلة في الأداء (performance)  !    

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

كالـ Textfield

لن تستطيع الضغط على الحقل بعد انتهاء الـ Animation

اذا كان الظاهر هو Presentation Layer

وليس الـ Layer الحقيقي الـ Actual Layer

 

لذا يفضل عدم استخدام الحل ذا قدر الإمكان ، ستحتاجه في بعض الحالات ولكن أغلب الحالات يفضل تغير موقع الـ Actual Layer بعد انتهاء الـ Animation كما تم شرحه في الحل الأول وهو الحل الذي سوف نستمر في استخدامه .

 

 

 

الان

قبل الضغط على الزر سوف يكون على شكل مربع

ومن ثم يحدث الـ Animation

فيتغير من الشكل المربع الى الدائرة

وعندما ينتهي الـ Animation

يظل على الشكل النهائي الذي هو الدائرة !

 

النتيجة :

 

5965737682b9e_Jul-03-201701-18-56.gif.6b8fbae63ea81f9dfaa7602c746f40c6.gif

 

حان الوقت لتوضيح معلومة =)

 

أعتقد بأنك لاحظت امراً

وهو خصائص الـ Aniamtion

في الـ Layer Animation

ليست مرتبطة بـ View  معين

بما يعني يمكنك إعادة عمل الـ Animation

ذاته على كذا View مختلف

 

لذا يمكنك إضافة مربع اخر

 

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

596573a201825_ScreenShot2017-07-01at10_16_36PM.thumb.png.e3a9aacd0b4c114b4ad7b82ec0f2585d.png

قم بتسميته باسم squareView2

ومن ثم قم بربطة بملف الاكواد

 

واستخدام نفس السطر التالي


 


   squareView2.layer.add(cornerRadiusAnimation, forKey: nil)

 

لاحظ التغير الوحيد squareView غيرناه الى squareView2

وهو يساوي اسم الـ view الجديد

 

ولا تنسى في النهاية تضيف السطر التالي


squareView2.layer.cornerRadius = 61

 

قم بتشغيل الكود وشاهد النتيجة :

596573d59c72c_Jul-03-201722-39-19.gif.d1fe1e1aff484a0c34b2a4802dc2ba2e.gif

 

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

 

الان وقد فهمت فكرة الـ Layer Animation

 

لنتحدث عن الانواع الأخرى :

 

التلاشي :
 


 let animation = CABasicAnimation(keyPath: "opacity")

        animation.duration = 0.5

        animation.fromValue = 1

        animation.toValue = 0

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.opacity = 0

 

بالنسبة للـ Layer

فالملكية المسؤولة عن الشفافية هي Opacity

عوضاً عن Alpha

 

اخر سطر كما وضحنا سابقا يتوجب علينا تغير القيمة الحقيقية أيضا

لكي يظل مخفي الـView بعد انتهاء الـ Animation

 

النتيجة :

596574014682a_Jul-05-201700-08-54.gif.e684cdbf173144bfff157628fcb18d6f.gif

 

إضافة ايطار – تغير حجم الايطار :

 

من خواص الـ Layer

الـ ايطار

يمكن وضع ايطار للـ View

 

بكتابة التالي في داخل الـ AnimationButton:


 


        let animation = CABasicAnimation(keyPath: "borderWidth")

        animation.duration = 0.5

        animation.fromValue = 0

        animation.toValue = 6

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.borderWidth = 6

بما سبق قمنا بتغير قيمة borderWidth

من صفر الى 6

 

النتيجة :

596578637487a_Jul-12-201704-15-51.gif.a2abf114de6be0fea94b8f7f879af250.gif

 

تغير لون الايطار :

 

الان سوف نضيف ايطار مسبقا في الـ Viewdidload()

ومن ثم نعمل Aniamtion

ونغير لونه عند الضغط على الزر

 

لذا قم بإضافة السطر التالي في Viewdidload()


squareView.layer.borderWidth = 6

الان بداخل قواس AnimationButton

قم بكتابة التالي :


 


let animation = CABasicAnimation(keyPath: "borderColor")

        animation.duration = 0.5

        animation.fromValue = UIColor.black.cgColor

        animation.toValue = UIColor.lightGray.cgColor

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.borderColor = UIColor.lightGray.cgColor

قمنا بتغير لون الحدود (الايطار) من اللون الأسود الى اللون الرصاصي الفاتح

 

ملاحظة مهمه :

في الـ Layer

في الألوان نستخدم نوع cgColor

وليست UIColor

لذلك نعمل عملية Casting لتحويل اللون الى نوع cgColor

اذا لم تضيف .cgColor

سيظهر خطأ !

 

النتيجة :

59657466d37bf_Jul-05-201702-35-11.gif.a8fbe553ce81e18cb33577cac7fd9bb6.gif

 

عمل Animation للظل ! :

 

بالنسبة للظل هناك 4 أمور تؤثر على الظل

shadowOpacity : شفافية الظل ، 0 تعني اختفاء الظل و 1 ظهوره

shadowOffset : موقع الظل

shadowRadius : كثافة الظل ، كل ما زاد الرقم اصبح "عرض" الظل اكبر

shadowColor : لون الظل

 

 

 

 

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

 


        let animation = CABasicAnimation(keyPath: "shadowOpacity")

        animation.duration = 0.5

        animation.fromValue = 0

        animation.toValue = 1

        

        squareView.layer.add(animation, forKey: nil)

        squareView.layer.shadowOpacity = 1

 

كما ذكرت سابقا قيمة 1 تعني ظهور الظل

لذا وضعنا قيمة 1

 

النتيجة :

59657491f32a8_Jul-09-201718-44-58.gif.7ff043ebc7c90920bd12de939c0c5574.gif

 

الان لغرض استخدام الخصائص الأخرى

 

سوف نقوم بكتابة الكود التالي في viewDidLoad


 


squareView.layer.shadowOpacity = 1

 

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

 

لتغير موقع الظل :
 


        let animation = CABasicAnimation(keyPath: "shadowOffset")

        animation.duration = 0.5

        animation.fromValue = CGSize.zero

        animation.toValue = CGSize(width: 5, height: 8)

                                                  

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.shadowOffset = CGSize(width: 5, height: 8)

 

النتيجة :

596574bd58bff_Jul-09-201719-02-04.gif.acd4469ff7c170e244f3763a394683ed.gif

 

لاحظ بأن shadowOffset يأخد قمتين وهما العرض width والارتفاع height

 

لتسهيل فهمها لاحظ الصورة التالية :

Zm8XO.png.cded14cbba0fa4be096711e5a818b54e.png

اذا اردت الظل يظهر من الجهة اليمين

اجعل القيم بالشكل التالي


CGSize(width: 8, height: 0)

 

من اليسار


CGSize(width: -8, height: 0)

 

من الأعلى


CGSize(width: 0, height: -8)

 

من الأسفل


CGSize(width: 0, height:8)

 

بما يعني اعتبر القيمتين x و y

وتذكر الصورة التالية :


 

6.thumb.png.6cb806d45c908d143fa182aa8311387a.png

 

لزيادة مساحة الظل :

 

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


 


        let animation = CABasicAnimation(keyPath: "shadowRadius")

        animation.duration = 0.5

        animation.fromValue = 0

        animation.toValue = 10

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.shadowRadius = 10

 

النتيجة :

596576d31ce7c_Jul-09-201719-12-20.gif.5a926863366f1aa6b6c51f7d834b5202.gif

 

لتغير لون الظل :

 

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


 


        let animation = CABasicAnimation(keyPath: " shadowColor")

        animation.duration = 0.5

        animation.fromValue = UIColor.black.cgColor

        animation.toValue = UIColor.gray.cgColor

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.shadowColor = UIColor.gray.cgColor

 

النتيجة :

59657731795ec_Jul-09-201719-18-58.gif.f6274a31700fdd3e31a7aa2360ae28ae.gif

 

وبكذا نكون انتهينا من خصائص الظل

 

 

الان نعود الى الامثله التي ذكرناها في المواضيع السابقة عندما تحدثنا عن UIView Animation

وكيف نفعلها باستخدام الـ Layer Animation

 

تغير موقع الـ View :

 

لتغير الموقع نستخدم ملكية تسمى Position

 

لاجل تغير قيمة y فقط نقوم بكتابة position.y

 


        let animation = CABasicAnimation(keyPath: "position.y")

        animation.duration = 0.5

        animation.fromValue = 126

        animation.toValue = 400

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.position.y = 400

 

 

fromValue

هو قيمة y الحالية 126

ونريد تغيرها الى قيمة 400

لجعل المربع ينزل الى الأسفل

 

النتيجة :

 

59657767e719a_Jul-09-201719-38-34.gif.420bf4c8fffcbbf3b58031810c220135.gif

 

 

لاجل تغير قيمة x فقط نقوم بكتابة position.x


 


        let animation = CABasicAnimation(keyPath: "position.x")

      

        animation.duration = 0.5

        animation.fromValue = squareView.center.x

        animation.toValue = -20

        

        squareView.layer.add(animation, forKey: nil)

        

        squareView.layer.position.x = -20

 

كما تلاحظ في formValue

قمنا بكتابة squareView.center.x

والسبب لجلب قيمة x لـ  View الحالية بدلاً من كتابتها بشكل يدوي

 

النتيجة :

5965778e3f74f_Jul-12-201702-26-05.gif.bbbf90742b4c558ce7bcdab510478bf8.gif

 

التصغير :

 


   let animation = CABasicAnimation(keyPath: "transform.scale")

       animation.isRemovedOnCompletion = false

animation.fillMode = kCAFillModeForwards

        

        animation.duration = 0.5

        animation.fromValue = 1

        animation.toValue = 0.8

        

        squareView.layer.add(animation, forKey: nil)

 

النتيجة :

596577a91a798_Jul-12-201703-11-34.gif.00cdb7370a950997a4016217de53ca65.gif

 

التضخيم :


 


let animation = CABasicAnimation(keyPath: "transform.scale")

       animation.isRemovedOnCompletion = false

animation.fillMode = kCAFillModeForwards

        

        animation.duration = 0.5

        animation.fromValue = 1

        animation.toValue = 2

        

        squareView.layer.add(animation, forKey: nil)

 

النتيجة :

596577c42c074_Jul-12-201703-12-11.gif.692815c0f5d026e17c3fad54b003af93.gif

 

معلومة :

 

اذا اردت فقط تصغير او تضخيم قيمة X دون Y

قم بكتابة

 


let animation = CABasicAnimation(keyPath: "transform.scale.x")

 

الأمر أيضا ينطبق على Y اذا اردت تصغير او تضخيم قيمة Y دون x

قم بكتابة

 


let animation = CABasicAnimation(keyPath: "transform.scale.x")

 

 

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

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

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

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