في هذا البرنامج التعليمي ، سنتعلم كيفية تخطيط تطبيقات واجهة المستخدم باستخدام طريقة العرض ومعرفة كيفية استخدام
متغيرات الحالة لتعديل واجهة المستخدم.
يقدر وقت القراءة: 25 دقيقة.
SwiftUI يسمح لنا أن ننسى تماما عن واجهة البناء (IB) واللوحات المصورة. كانت IB و Xcode تطبيقين منفصلين قبل Xcode 4 ، ولكن "الإرساء" بينهما لا يزال مرئيًا عندما نقوم بتحرير اسم IBAction أو IBOutlet وتعطل تطبيقنا ، لذلك لا يعرف IB أي شيء عن التغييرات في الرمز. أو عندما نقوم بتعيين معرفات للجداول أو لخلايا الجدول ، ولكن Xcode لا يمكن التحقق منها ، لأنها سلسلة.
SwiftUI لانقاذ! نرى على الفور التغييرات في طريقة العرض بمجرد إدخال الرمز. التغييرات في جانب واحد ينتج عنها تحديث من الجانب الآخر ، لذلك فهي مرتبطة دائمًا. لا توجد معرفات السلسلة التي يمكن أن تكون خاطئة. هذه هي كل الشفرة ، لكنها أصغر بكثير مما لو كتبناها باستخدام UIKit ، لذلك فمن الأسهل فهمها وتعديلها وتصحيحها. أخبرني ، أليس هذا رائعًا؟
دعنا نذهب
لنبدأ مشروعًا جديدًا في مشروع Xcode (
Shift-Command-N ) ، وحدد
تطبيق iOS ▸ Single View ، واتصل بـ RGBullsEye ، وتأكد من اختيار
SwiftUI كواجهة.
الآن
يتم تقسيم
AppDelegate.swift إلى ملفين:
AppDelegate.swift و SceneDelegate.swift ، ويحتوي SceneDelegate على نافذة:

لا يرتبط
SceneDelegate تقريبًا بـ SwiftUI ، باستثناء هذا السطر:
window.rootViewController = UIHostingController(rootView: ContentView())
UIHostingController ينشئ وحدة تحكم عرض لـ ContentView لـ
SwiftUI .
ملاحظة: UIHostingController يسمح لنا بدمج SwiftUI-view في تطبيق موجود. أضف وحدة التحكم في عرض الاستضافة إلى لوحة العمل الخاصة بنا وقم بإنشاء سلسلة عليها من UIViewController. ثم نستخدم Control-drag مع segue على رمز وحدة التحكم في طريقة العرض لإنشاء IBSegueAction ، حيث نقوم بتعيين وحدة تحكم الاستضافة على rootView - SwiftUI-view.
عند بدء تشغيل التطبيق ، تعرض النافذة مثيل
ContentView ، والذي يتم تعريفه في ملف
ContentView.swift . هذا هيكل يتوافق مع بروتوكول
العرض :
struct ContentView: View { var body: some View { Text("Hello World") } }
هذا هو إعلان SwiftUI لمحتويات ContentView (النص الأساسي). يوجد الآن طريقة عرض نص مع النص Hello World.
أسفل ContentView_Previews مباشرة بإرجاع مثيل ContentView.
struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
هنا يمكننا ضبط بيانات الاختبار للمعاينة. لكن أين هذه المعاينة بالضبط؟
مباشرة بعد الرمز هو مساحة فارغة كبيرة مع هذا أعلاه:

انقر فوق
استئناف ، انتظر لحظة و ...

رسم لدينا واجهة المستخدم
شيء مألوف غير مرئي - هذا هو ملف
Main.storyboard . سنقوم بإنشاء واجهة المستخدم الخاصة بنا باستخدام SwiftUI ، مباشرة في الكود ، في عملية النظر إلى المعاينة: ماذا نصل إلى هناك؟ ولكن لا تقلق ، لا يتعين علينا كتابة مئات أسطر التعليمات البرمجية لإنشاء وجهات نظرنا.
SwiftUI هو إعلان: عليك تحديد شكل واجهة المستخدم الخاصة بك ، ويقوم SwiftUI بتحويل كل هذا إلى رمز فعال يقوم بكل العمل. تسمح لك Apple بإنشاء أكبر عدد ممكن من المشاهدات لجعل الكود بسيطًا ومباشرًا. يوصى بشكل خاص باستخدام طرق العرض القابلة لإعادة الاستخدام مع المعلمات - وهذا مشابه لتخصيص التعليمات البرمجية في وظيفة منفصلة. سوف تفعل ذلك بنفسك في وقت لاحق.
سيحتوي تطبيقنا على عدد كبير من المشاهدات ، لذلك في البداية سنقوم برسم طرق عرض النص كنقاط متابعة.
يستعاض عن النص ("Hello World") بهذا:
Text("Target Color Block")
إذا لزم الأمر ، انقر فوق "
استئناف" لتحديث المعاينة.
الآن
، اضغط على
Command في طريقة العرض هذه في
المعاينة ، وحدد
Embed in HStack :

يرجى ملاحظة أن الكود قد تغير أيضًا:
HStack { Text("Target Color Block") }
انسخ والصق مشغل النص وقم بتحريره داخل HStack الخاص بنا. يرجى ملاحظة: نحن لا نفصل بين المشغلين بفاصلة ، ولكن نكتب كل منهم على سطر جديد:
HStack { Text("Target Color Block") Text("Guess Color Block") }
وهكذا يبدو في المعاينة:

الآن دعنا نعد مكانًا
لعوب المنزلق بوضع
HStack على
VStack . هذه المرة سنفعل
Command-Click على HStack
في الكود الخاص بنا :

اختر
تضمين في VStack ؛ سيظهر رمز جديد ، لكن المعاينة لن تتغير. بعد ذلك بقليل سنضيف طريقة عرض تحت كتل اللون المستقبلية.
أضف خطًا جديدًا بعد HStack مباشرةً ، انقر فوق
+ على شريط الأدوات لفتح المكتبة واسحب خط
عمودي مكدس إلى سطر جديد:

كما هو متوقع ، تم تغيير كل من الكود والمعاينة:

إنهاء العمل على مشروع واجهة المستخدم ، بحيث يبدو كل شيء كما يلي:
VStack { HStack { Text("Target Color Block") Text("Guess Color Block") } Text("Hit me button") VStack { Text("Red slider") Text("Green slider") Text("Blue slider") } }
في VStack الجديد ، ستظهر ثلاثة مربعات تمرير لاحقًا ، بالإضافة إلى زر بين المنزلق وكتل الألوان.
نواصل العمل على واجهة المستخدم
الآن دعونا نمارس في SwiftUI لملء HStack يحتوي على كتل ملونة:
HStack {
كل كتلة اللون لديها مستطيل. تحتوي كتلة اللون الهدف (الهدف) على عرض نص واحد أسفل المستطيل ، بينما تحتوي كتلة اللون المستهدفة (تخمين) على ثلاثة نص. بعد ذلك بقليل سنستبدل "xxx" بالقيم الحقيقية للانزلاق.
استخدام المتغيرات 'State'
في SwiftUI ، يمكننا استخدام المتغيرات العادية ، ولكن إذا أردنا أن يؤثر تغيير المتغير على واجهة المستخدم ، فإننا نحتفل بمتغيرات مثل
"State" . في تطبيقنا ، نختار اللون ، بحيث تكون جميع المتغيرات التي تؤثر على اللون المحدد متغيرات "State".
أضف هذه السطور داخل
بنية ContentView ، قبل الإعلان الأساسي:
let rTarget = Double.random(in: 0..<1) let gTarget = Double.random(in: 0..<1) let bTarget = Double.random(in: 0..<1) @State var rGuess: Double @State var gGuess: Double @State var bGuess: Double
تقع قيم R و G و B بين 0 و 1. نقوم بتهيئة القيم المطلوبة بقيم عشوائية. يمكننا أيضًا تهيئة القيم المحددة إلى 0.5 ، ولكن نتركها غير مهيأة الآن لإظهار ما يجب القيام به في هذه الحالة.
دعنا
ننتقل قليلاً إلى
بنية ContentView_Previews ، التي تهيئ مثيل ContentView
للمعاينة . الآن يحتاج المُهيئ إلى القيم الأولية للقيم المحددة. تغيير
ContentView () مثل هذا:
ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5)
عندما نصنع المتزلجون ، في المعاينة ستكون قيمهم في المنتصف.
يجب علينا أيضًا إصلاح
المُهيئ في
SceneDelegate ، في وظيفة
المشهد (_: willConnectTo: options :) - استبدال
ContentView () بما يلي:
window.rootViewController = UIHostingController(rootView: ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5))
عند تحميل التطبيق ، ستكون مؤشرات شريط التمرير في المنتصف.
أضف الآن معدلاً للألوان إلى المستطيل الهدف:
Rectangle() .foregroundColor(Color(red: rTarget, green: gTarget, blue: bTarget, opacity: 1.0))
يقوم معدّل
.foregroundColor بإنشاء طريقة عرض Rectangle جديدة باللون المحدد بواسطة قيم RGB التي تم إنشاؤها عشوائيًا.
وبالمثل ، قم بتعديل مستطيل التخمين:
Rectangle() .foregroundColor(Color(red: rGuess, green: gGuess, blue: bGuess, opacity: 1.0))
مع قيم R و G و B عند 0.5 نحصل على لون رمادي.
انقر فوق استئناف وانتظر لحظة.

جعل عرض قابلة لإعادة الاستخدام
أولاً ، لن نفكر في إعادة الاستخدام ونقوم فقط بعمل شريط تمرير باللون الأحمر. في
VStack for sliders ،
استبدل النص Text ("Red slider") بقابس
HStack هذا:
HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) }
لقد جعلنا لون النص في عرض النص أحمر. وأضافوا المتزلج مع القيمة الافتراضية. يتراوح النطاق الافتراضي لشريط التمرير من 0 إلى 1 ، وهذا شيء يناسبنا تمامًا.
ملاحظة: نعلم أن شريط التمرير ينتقل من 0 إلى 1 ، وأن تسمية النص هي "255" لراحة المستخدمين الذين اعتادوا على تمثيل قيم RGB في النطاق من 0 إلى 255.
ولكن ما هو أيقونة
$ للمتغير؟ هل نعرف عنها
؟ و! عند العمل مع
اختياري ، والآن أيضا
$ ؟
على الرغم من حقيقة أنه صغير جدًا وغير واضح ، إلا أنه مهم جدًا.
RGuess نفسها هي مجرد قيمة
للقراءة فقط. لكن
$ rGuess ملزم ، نحتاجه لتحديث مستطيل اللون المحدد عندما يقوم المستخدم بتحريك شريط التمرير.
لفهم الفرق ، قم بتعيين قيم عرض النص الثلاثة ضمن المستطيل القابل للتنبؤ:
HStack { Text("R: \(Int(rGuess * 255.0))") Text("G: \(Int(gGuess * 255.0))") Text("B: \(Int(bGuess * 255.0))") }
هنا نستخدم القيم فقط ، ولا نغيرها ، لذلك نحن لسنا بحاجة إلى بادئة $.
انتظر تحديث المعاينة:

انكمشت المستطيلات الملونة قليلاً لتناسب المنزلق. لكن تسميات نص شريط التمرير تبدو غير واضحة - فهي مضغوطة للغاية على الحواف. دعنا نضيف معدلاً آخر إلى HStack - الحشو:
HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } .padding()
الآن أفضل بكثير!

جعل
Command-Click على شريط التمرير الأحمر HStack ، وحدد
Extract Subview :

يعمل هذا تمامًا مثل
Refactor ▸ Extract to Function ، ولكن لعرض SwiftUI.
عند هذه النقطة ، ستظهر عدة رسائل خطأ ، لا تقلق ، والآن سنصلحها.
قم بتسمية العرض الناتج
ColorSlider وأضف هذا الرمز في الأعلى ، أمام نص العرض الجديد:
@Binding var value: Double var textColor: Color
استبدل الآن
$ rGuess بقيمة $ ، و .red بنص اللون :
Text("0") .foregroundColor(textColor) Slider(value: $value) Text("255") .foregroundColor(textColor)
دعنا نعود إلى تعريف ColorSlider () في VStack وإضافة المعلمات لدينا:
ColorSlider(value: $rGuess, textColor: .red)
تأكد من أن المعاينة على ما يرام مع شريط التمرير الأحمر واستبدال كعب الروتين النص مع منزلقات خضراء وزرقاء. لا تنسَ إدراج المعلمات الصحيحة هناك:
ColorSlider(value: $gGuess, textColor: .green) ColorSlider(value: $bGuess, textColor: .blue)
انقر فوق
استئناف لتحديث المعاينة:

ملاحظة: ربما لاحظت أنه عليك غالبًا النقر فوق استئناف . إذا كنت تحب الاختصارات ، فربما تحب الخيار Option-Command-P .
والآن شيء جميل! في الركن الأيمن السفلي من المعاينة ، انقر فوق زر
المعاينة المباشرة :

المعاينة المباشرة تتيح لنا التفاعل مع المعاينة كما لو كان التطبيق يعمل على جهاز محاكاة!
حاول تحريك شريط التمرير:

! رائع نمر إلى المرحلة النهائية. بعد كل شيء ، نريد أن نعرف جيدا كيف اخترنا اللون؟
عرض تنبيه
بعد ضبط شريط التمرير على المواضع المطلوبة ، يضغط المستخدم على الزر
Hit Me ، وبعد ذلك يظهر
التنبيه بتصنيف.
أولاً ، أضف طريقة إلى ContentView لحساب النتيجة. بين المتغيرات @ الدولة و
إضافة الجسم هذه الطريقة:
func computeScore() -> Int { let rDiff = rGuess - rTarget let gDiff = gGuess - gTarget let bDiff = bGuess - bTarget let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff) return Int((1.0 - diff) * 100.0 + 0.5) }
قيمة
الفرق هي ببساطة المسافة بين نقطتين في الفضاء ثلاثي الأبعاد ، أي قيمة خطأ المستخدم. للحصول على تقدير ، قم بطرح الفرق من 1 ، ثم قم بتخفيض قيمته إلى النطاق من 0 إلى 100. كلما كان الفرق أصغر ، كلما زاد التقدير.
ثم استبدل كعب
النص ("Hit me button") بالكود التالي:
Button(action: { }) { Text("Hit Me!") }
زر لديه عمل والتسمية ، مثل UIButton. نريد إجراءً لتحريك عرض تنبيه. ولكن ، إذا أنشأنا تنبيه في زر الإجراء ، فلن يحدث شيء.
بدلاً من ذلك ، سنجعل Alert جزءًا من ContentView ، ونضيف متغير "State" من النوع Bool. بعد ذلك ، قمنا بتعيين هذا المتغير على true ، في المكان الذي نريد أن يظهر فيه تنبيهنا في زر الإجراء. سيتم إعادة تعيين القيمة إلى خطأ - لإخفاء التنبيه - عندما يخفي المستخدم التنبيه.
أضف هذا المتغير "State":
@State var showAlert = false
ثم أضف هذا الرمز كزر إجراء:
self.showAlert = true
النفس ضرورية بالنسبة لنا ، لأن showAlert داخل الإغلاق.
أخيرًا ، أضف مُعدِّل التنبيه إلى الزر ، لذلك يبدو الزر لدينا كما يلي تمامًا:
Button(action: { self.showAlert = true }) { Text("Hit Me!") } .alert(isPresented: $showAlert) { Alert(title: Text("Your Score"), message: Text("\(computeScore())")) }
إننا نعتبر $ showAlert بمثابة رابط ، لأن قيمة هذا المتغير ستغير اللحظة التي يخفي فيها المستخدم التنبيه ، وسيؤدي هذا التغيير إلى تحديث طريقة العرض.
SwiftUI لديه أداة تهيئة بسيطة لعرض التنبيه. يحتوي على زر "موافق" افتراضيًا ، لذلك لا نحتاج حتى إلى تعيينه كمعلمة.
قم بتشغيل المعاينة المباشرة ، وانقل المنزلقين واضغط على الزر Hit me. فويلا!

الآن مع المعاينة المباشرة ، لم تعد بحاجة إلى محاكاة iOS. على الرغم من أنه يمكنك اختبار التطبيق الخاص بك أفقياً:

استنتاج
هنا يمكنك تنزيل مسودة المنشور النهائي.
لقد غطى هذا البرنامج التعليمي SwiftUI قليلاً فقط ، لكن الآن لديك انطباع بالميزات الجديدة لـ Xcode لإنشاء واجهات مستخدم ومعاينات ، وكذلك كيفية استخدام متغيرات "State" لتحديث واجهة المستخدم الخاصة بك.
للبساطة ، لم نقم بإنشاء نموذج بيانات لـ RGB. لكن معظم التطبيقات تنشئ نماذج لبياناتها باستخدام هياكل أو فئات. إذا كنت ترغب في تتبع التغييرات في النموذج في SwiftUI ، فيجب أن يتوافق مع بروتوكول
ObservableObject وتنفيذ خاصية
willChange ، التي
تُعلمك بالتغييرات.
تحقق من أمثلة Apple وخاصة
تدفق البيانات عبر SwiftUI .
لتسهيل فهم SwiftUI ، يمكنك إضافة طريقة عرض SwiftUI إلى تطبيق موجود. انظر أمثلة لكيفية القيام بذلك بسرعة وسهولة.
انظر
المنشور الخاص
بي حول تطبيق القوائم القابلة للطي / المنسدلة باستخدام SwiftUI.
أخيرًا ، ادرس
الوثائق الخاصة بـ SwiftUI ، وهناك بالفعل الكثير من
الأشياء المفيدة!