تم إعداد ترجمة المقال عشية إطلاق الدورة المتقدمة "iOS Developer" .
أهلا ومرحبا بكم في برنامجنا التعليمي! في هذه السلسلة ، نتحدث عن كيفية التنقل بين طرق العرض في SwiftUI (بدون استخدام عرض التنقل!). على الرغم من أن هذه الفكرة قد تبدو تافهة ، ولكن بعد فهمها أعمق قليلاً ، يمكننا معرفة الكثير عن مفاهيم تدفق البيانات المستخدمة في SwiftUI.في الجزء السابق ، تعلمنا كيفية تنفيذ ذلك باستخدام @ObservableObject
. في هذا الجزء ، سننظر في كيفية القيام بنفس الشيء ، ولكن بكفاءة أكبر باستخدامEnvironmentObject. سنضيف أيضًا القليل من الرسوم المتحركة الانتقالية.إليك ما سنحققه:ما لدينا
لذا ، توصلنا للتو إلى كيفية التنقل بين طرق العرض المختلفة باستخدام ObservableObject. باختصار ، أنشأنا ViewRouter وربطناه بـ Mother View و Content View. بعد ذلك ، نقوم ببساطة بمعالجة خاصية CurrentPage ViewRouter بالنقر فوق أزرار عرض المحتوى. بعد ذلك ، يتم تحديث MotherView لعرض "عرض المحتوى" المطابق!ولكن هناك طريقة ثانية أكثر كفاءة لتحقيق هذه الوظيفة: استخدم @EnvironmentObject
!تلميح: يمكنك تنزيل آخر التطورات هنا (هذا هو المجلد "NavigateInSwiftUIComplete") : GitHubلماذا الاستخدام ObservableObject
ليس هو الحل الأفضل
ربما تتساءل: لماذا يجب علينا تنفيذ ذلك بأي طريقة أخرى ، عندما يكون لدينا بالفعل حل عملي؟ حسنًا ، إذا نظرت إلى منطق التسلسل الهرمي لتطبيقنا ، فسوف يتضح لك. MotherView الخاص بنا هو العرض الجذر الذي يقوم بتهيئة مثيل ViewRouter. في MotherView ، نقوم أيضًا بتهيئة ContentViewA و ContentViewB ، ونمررهما مثيل ViewRouter باعتباره BindableObject.كما ترون ، يجب أن نتبع تسلسلًا هرميًا صارمًا يقوم بتمرير ObservableObject المهيأ لجميع طرق العرض الفرعية. الآن هذا ليس مهمًا جدًا ، ولكن تخيل تطبيقًا أكثر تعقيدًا مع الكثير من المشاهدات. نحتاج دائمًا إلى تتبع إرسال عرض الجذر القابل للرصد الأولي إلى جميع طرق العرض الفرعية وجميع طرق العرض الفرعية لوجهات النظر الفرعية ، وما إلى ذلك ، والتي يمكن أن تكون في النهاية مهمة شاقة.
لتلخيص: استخدام التنظيف ObservableObject
يمكن أن يكون مشكلة عندما يتعلق الأمر بتسلسل هرمي أكثر تعقيدًا للتطبيق.بدلاً من ذلك ، يمكننا تهيئة ViewRouter عند بدء تشغيل التطبيق بحيث يمكن ربط جميع طرق العرض مباشرة بهذا المثيل ، أو بالأحرى مشاهدته ، بغض النظر عن التسلسل الهرمي للتطبيق. في هذه الحالة ، سيبدو مثيل ViewRouter بمثابة سحابة تتنقل فوق رمز تطبيقنا ، والتي تصل إليها جميع المشاهدات تلقائيًا دون القلق بشأن سلسلة التهيئة الصحيحة أسفل التسلسل الهرمي للعرض.هذه هي الوظيفة فقط EnvironmentObject
!ما هو EnvironmentObject
؟
EnvironmentObject
هو نموذج بيانات يمكنه ، بعد التهيئة ، تبادل البيانات مع جميع تمثيلات تطبيقك. ما هو جيد بشكل خاص هو ما تم EnvironmentObject
إنشاؤه من خلال تقديم ObservableObject
، حتى نتمكن من استخدام ما لدينا ViewRouter
لخلق EnvironmentObject
!بمجرد إعلاننا ViewRouter
عن EnvironmentObject
وجهة نظرنا ، يمكن إرفاق جميع المشاهدات بها وكذلك العروض العادية ObservableObject
، ولكن دون الحاجة إلى سلسلة من التهيئة أسفل التسلسل الهرمي للتطبيق!كما سبق ذكره ، EnvironmentObject
يجب أن تتم تهيئته بالفعل في المرة الأولى التي يتم الوصول إليه. نظرًا لأننا MotherView
، كعرض الجذر ، سوف ننظر إلى الخاصية CurrentPage
ViewRouter
، يجب أن نهيئها EnvironmentObject
عند بدء التطبيق. ثم يمكننا تغيير الصفحة الحالية تلقائيًاEnvironmentObject
من ContentView
، والذي يتطلب بعد ذلك MotherView
إعادة العرض.
التنفيذ على ViewRouter
النحوEnvironmentObject
لذا ، دعنا نقوم بتحديث رمز تطبيقنا!أولاً ، قم بتغيير غلاف الخاصية من viewRouter
الداخل إلى .MotherView
@ObservableObject
@EnvironmentObject
import SwiftUI
struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
الخاصية viewRouter
تبحث الآن ViewRouter-EnvironmentObject
. وبالتالي ، نحتاج إلى تزويد هيكلنا بالمثال MotherView_Previews
المناسب:#if DEBUG
struct MotherView_Previews : PreviewProvider {
static var previews: some View {
MotherView().environmentObject(ViewRouter())
}
}
#endif
كما ذكرنا أعلاه - عند بدء تطبيقنا ، يجب أن يتم توفيره على الفور بمثيل ViewRouter
في الجودة EnvironmentObject
، لأنه MotherView
يشير الآن إلى تمثيل الجذر EnvironmentObject
. لذلك ، قم بتحديث وظيفة المشهد داخل الملف على SceneDelegage.swift
النحو التالي:func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: MotherView().environmentObject(ViewRouter()))
self.window = window
window.makeKeyAndVisible()
}
}
رائع ، الآن عند بدء التطبيق ، يقوم SwiftUI بإنشاء مثيل ViewRouter
في الجودة EnvironmentObject
، يمكن الآن إرفاق جميع طرق عرض تطبيقنا به.بعد ذلك ، دعنا نقوم بتحديث موقعنا ContentViewA
. قم بتغيير خصائصه viewRouter
إلى EnvironmentObject
وتحديث البنية أيضًا ContentViewA_Previews
.import SwiftUI
struct ContentViewA : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
#if DEBUG
struct ContentViewA_Previews : PreviewProvider {
static var previews: some View {
ContentViewA().environmentObject(ViewRouter())
}
}
#endif
تلميح: مرة أخرى ، للهيكل ContentViewsA_Previews
مثيله الخاص ViewRouter
، ولكنه ContentViewA
مرتبط بالمثيل الذي تم إنشاؤه عند تشغيل التطبيق!دعنا نكرر هذا لـ ContentViewB
:import SwiftUI
struct ContentViewB : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
#if DEBUG
struct ContentViewB_Previews : PreviewProvider {
static var previews: some View {
ContentViewB().environmentObject(ViewRouter())
}
}
#endif
منذ viewRouter
لدينا هي الخصائص ContentView
المتعلقة الآن مباشرة إلى / مراقبة المثال الأولي ViewRouter
كما EnvironmentObject
أننا لم تعد بحاجة إلى تهيئة لهم في بلدنا MotherView
. لذا ، دعنا نقوم بتحديث MotherView
:struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
}
}
}
}
هذا أمر رائع: لم نعد بحاجة إلى التهيئة ViewRouter
داخل منطقتنا MotherView
وتمرير مثيله إلى ContentView ، والذي يمكن أن يكون فعالًا للغاية ، خاصة بالنسبة للتسلسلات الهرمية الأكثر تعقيدًا.رائع ، دعنا نشغل تطبيقنا ونرى كيف يعمل. رائع ، لا يزال بإمكاننا التنقل بين وجهات نظرنا!مضيفا الرسوم المتحركة الانتقالية
كمكافأة ، دعنا نلقي نظرة على كيفية إضافة رسم متحرك انتقالي عند التبديل من "page1" إلى "page2".في SwiftUI ، هذا بسيط للغاية.انظر إلى willChange
الطريقة التي نسميها الملف ViewRouter.swift
عند CurrentPage
التحديث. كما تعلمون بالفعل ، يؤدي هذا إلى إلزام MotherView
بإعادة عرض جسمك ، وفي النهاية إظهار آخر ContentView
، مما يعني الانتقال إلى آخر ContentView
. يمكننا إضافة رسوم متحركة ببساطة عن طريق لف الطريقة willChange
في دالة withAnimation
:var currentPage: String = "page1" {
didSet {
withAnimation() {
willChange.send(self)
}
}
}
يمكننا الآن إضافة رسم متحرك انتقالي عند عرض آخر Content View
."WithAnimation (_: _ :) - تُرجع نتيجة إعادة حساب جسم العرض باستخدام الرسوم المتحركة المتوفرة"
Apple
نريد تزويد تطبيقنا بانتقال منبثق عند الانتقال من ContentViewA
إلى ContentViewB
. للقيام بذلك ، انتقل إلى الملف MotherView.swift
وأضف معدّل الانتقال عند الاستدعاء ContentViewB
. يمكنك اختيار أحد أنواع الانتقال المحددة مسبقًا أو حتى إنشاء الخاصة بك (ولكن هذا موضوع لمقال آخر). لإضافة انتقال منبثق ، نختار نوعًا .scale
.var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
.transition(.scale)
}
}
}
لمعرفة كيفية عملها ، قم بتشغيل التطبيق الخاص بك في جهاز محاكاة عادي: رائع ، لقد أضفنا رسومًا متحركة لطيفة إلى تطبيقنا في بضعة أسطر من التعليمات البرمجية!يمكنك تنزيل جميع التعليمات البرمجية المصدر هنا !استنتاج
هذا كل شئ! لقد تعلمنا لماذا من الأفضل استخدام EnvironmentObject
التنقل بين طرق العرض في SwiftUI ، وكيفية تنفيذه. تعلمنا أيضًا كيفية إضافة الرسوم المتحركة الانتقالية للملاحة. إذا كنت تريد معرفة المزيد ، تابعنا على Instagram واشترك في نشرتنا الإخبارية حتى لا تفوتك التحديثات والبرامج التعليمية والنصائح حول SwiftUI والمزيد!
درس مجاني: "تسريع تطبيقات iOS بالأدوات"