أساسيات الـ Animation في Swift 3 الجزء الخامس
في هذا الجزء سوف ننتقل الي نوع اخر مختلف عنما اعتدنا عليه سابقا
سوف ننتقل من 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
الان نرى النتيجة في الصورة التالية :
كما ترى لم يتم حدوث 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
عند تغيره من مربع الى دائره
كما في الصورة التالية :
لكن هناك مشكلة !!
عند الانتهاء من الـ 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
يظل على الشكل النهائي الذي هو الدائرة !
النتيجة :
حان الوقت لتوضيح معلومة =)
أعتقد بأنك لاحظت امراً
وهو خصائص الـ Aniamtion
في الـ Layer Animation
ليست مرتبطة بـ View معين
بما يعني يمكنك إعادة عمل الـ Animation
ذاته على كذا View مختلف
لذا يمكنك إضافة مربع اخر
كما في الصورة التالية :
قم بتسميته باسم squareView2
ومن ثم قم بربطة بملف الاكواد
واستخدام نفس السطر التالي
squareView2.layer.add(cornerRadiusAnimation, forKey: nil)
لاحظ التغير الوحيد squareView غيرناه الى squareView2
وهو يساوي اسم الـ view الجديد
ولا تنسى في النهاية تضيف السطر التالي
squareView2.layer.cornerRadius = 61
قم بتشغيل الكود وشاهد النتيجة :
نعود الى الشرح
الان وقد فهمت فكرة الـ 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
النتيجة :
إضافة ايطار – تغير حجم الايطار :
من خواص الـ 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
النتيجة :
تغير لون الايطار :
الان سوف نضيف ايطار مسبقا في الـ 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
سيظهر خطأ !
النتيجة :
عمل 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
النتيجة :
الان لغرض استخدام الخصائص الأخرى
سوف نقوم بكتابة الكود التالي في 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)
النتيجة :
لاحظ بأن shadowOffset يأخد قمتين وهما العرض width والارتفاع height
لتسهيل فهمها لاحظ الصورة التالية :
اذا اردت الظل يظهر من الجهة اليمين
اجعل القيم بالشكل التالي
CGSize(width: 8, height: 0)
من اليسار
CGSize(width: -8, height: 0)
من الأعلى
CGSize(width: 0, height: -8)
من الأسفل
CGSize(width: 0, height:8)
بما يعني اعتبر القيمتين x و y
وتذكر الصورة التالية :
لزيادة مساحة الظل :
قم بكتابة الاكواد التالية :
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
النتيجة :
لتغير لون الظل :
قم بكتابة الاكواد التالية :
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
النتيجة :
وبكذا نكون انتهينا من خصائص الظل
الان نعود الى الامثله التي ذكرناها في المواضيع السابقة عندما تحدثنا عن 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
لجعل المربع ينزل الى الأسفل
النتيجة :
لاجل تغير قيمة 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 الحالية بدلاً من كتابتها بشكل يدوي
النتيجة :
التصغير :
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)
النتيجة :
التضخيم :
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)
النتيجة :
معلومة :
اذا اردت فقط تصغير او تضخيم قيمة X دون Y
قم بكتابة
let animation = CABasicAnimation(keyPath: "transform.scale.x")
الأمر أيضا ينطبق على Y اذا اردت تصغير او تضخيم قيمة Y دون x
قم بكتابة
let animation = CABasicAnimation(keyPath: "transform.scale.x")
التعليقات (0)
عرض المزيد.. جديد مقالاتي
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !