في يونيو ، سمعنا عن
SwiftUI لأول مرة - طريقة جديدة تمامًا لإنشاء عناصر واجهة المستخدم والعمل عليها في تطبيقات iOS و macOS (أيضًا iPadOS). شعرت وكأنها عيد الميلاد في الصيف. إنه جديد ، إنه إعلاني ، إنه مثير! والآن ، بعد بضعة أسابيع فقط من إصدار iOS 13 ، يمكننا البدء في استخدام SwiftUI في جميع مشاريعنا. دعونا نتعلم كيفية استخدام هذه الأداة المذهلة التي قدمتها لنا Apple ، لإنشاء بطاقات Swinder-esque الكلاسيكية.
في هذه المقالة ، أود أن أوضح لك كيفية تحقيق طريقة عرض بطاقة Tinder-like وسلوكها (التمرير السريع إلى العمل) ، مع بضعة أسطر من التعليمات البرمجية فقط.
لتحقيق ذلك ، نحتاج إلى القيام بالأمور التالية ، بالترتيب:
- إنشاء UserView
- إنشاء navigationview
- إنشاء BottomBarView
- إنشاء swipeview
- ضع كل هذا معًا داخل ContentView
لذلك دعونا نبدأ.
UserView
تم تصميم UserView من عرضين فرعيين ، الأول هو
NameView الذي يحتوي على اسم المستخدم والعمر والهوايات ،
والعرض الثاني هو مجرد عرض الصورة الرمزية التي تعرض صورة ملف تعريف المستخدم.
struct NameView: View { let name: String let age: Int let hobby: String var body: some View { VStack(alignment: .leading) { Spacer() Text("\(name), \(age)") .font(.title) .fontWeight(.semibold) .foregroundColor(.white) Text(hobby) .font(.system(size: 16)) .fontWeight(.regular) .foregroundColor(.white) } .padding() } }
أولاً ، نحتاج إلى تحديد
NameView ،
سيمثل هذا اسم المستخدم والعمر والهواية.
NameView يتوافق مع بروتوكول
العرض ، والذي يستخدم لتحديد طرق العرض المخصصة في SwiftUI. يحتوي بروتوكول العرض على شرط واحد فقط وهو تحديد خاصية الجسم التي يجب أن تُرجع بنية العرض وتصف سلوكها. يمكنك التحقق من المزيد حول بروتوكول
العرض في
وثائق Apple الرسمية.
دعنا نحلل الكائنات التي نستخدمها لتحديد
طريقة العرض هذه:
- VStack الذي يعمل مثل حاوية لجميع الكائنات محاذاة لهم عموديا
- فاصل يخبر SwiftUI أنه يجب محاذاة هذا العرض في الأسفل
- النص الذي يمثل التسمية مع الاسم والعمر ، مع الخصائص التالية:
- كائن النص الثاني الذي يحتوي على خصائص مشابهة ويعرض هواية المستخدم
يرجى ملاحظة أننا لا نستخدم بيان الإرجاع هنا ، داخل خاصية الجسم ، ولكن بدلاً من ذلك ، فإننا نعيد VStack. يستخدم SwiftUI اقتراح omit-return المطبق في Swift 5.0. يمكنك التحقق من المزيد حول هذا
هنا .
AvatarView
هذه هي الطريقة التي يتم تعريف
AvatarView :
struct AvatarView: View { let image: UIImage var body: some View { Image(uiImage: image) .resizable() .overlay( Rectangle() .fill(LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .center, endPoint: .bottom)) .clipped() ) .cornerRadius(12.0) } }
دعنا نتصفح المكونات التي تصنع وحدة الصورة الرمزية هذه:
- صورة - والتي تعرض صورة المستخدم
- يمكن تغيير حجمها - تحدد هذه الطريقة أنه يجب تغيير حجم الصورة لتناسب المكان الذي تم تضمينه فيه
- تراكب (مستطيل) - هنا نعرّف التدرج اللوني الذي سيكون خلفية جميلة لـ NameView ، يبدأ هذا التدرج اللوني في مركز الصورة وينتهي في الأسفل ، ولونه واضح في البداية والأسود في الأسفل
- cornerRadius - الصورة سيكون لها دائرة نصف قطرها يحشر
والآن ، دعونا
ندمج هذين العرضين في طريقة عرض حاوية واحدة باسم
UserView .
UserView
struct UserView: View { let userModel: UserModel var body: some View { ZStack(alignment: .leading) { AvatarView(image: userModel.image) NameView(name: userModel.name, age: userModel.age, hobby: userModel.hobby) } .shadow(radius: 12.0) .cornerRadius(12.0) } }
إليك ما يجري:
- ZStack - هذه طريقة عرض مكدس من شأنها محاذاة أطفالها على نفس المحور. يمكنك قراءة المزيد عن ZStack هنا
- AvatarView - لدينا عرض الرمزية التي تحتوي على الصورة المقدمة عبر UserModel
- NameView - عرض اسمنا يعرض الاسم بناءً على طراز المستخدم
بعد كل هذه الخطوات ، قم بتشغيل التطبيق. ستحصل على الشاشة التالية:
دعنا نضيف الآن طريقة مساعدة صغيرة. قبل أن أريك كيف يتم تعريف NavigationView ، فلننشئ طريقة مساعدة ، تبدو كما يلي:
struct ViewFactory { static func button(_ name: String, renderingMode: Image.TemplateRenderingMode = .original) -> some View { Button(action: {}) { Image(name) .renderingMode(renderingMode) } } }
هنا ، قمنا بتعريف طريقة مصنع الأزرار ، والتي تنشئ زرًا جديدًا من صورة معينة ووضع التقديم. لا يوجد أي معالج إجراءات ، حيث أن ذلك خارج عن نطاق هذه المقالة.
NavigationView
struct NavigationView: View { var body: some View { HStack { ViewFactory.button("profile_icon") Spacer() ViewFactory.button("fire_icon") .scaleEffect(2) Spacer() ViewFactory.button("chat_icon") } } }
سوف SwiftUI تلقائيا جعل
الفواصل متساوية في العرض ، وسوف تعطينا عرض التنقل التالي:
BottomBarView
struct BottomBarView: View { var body: some View { HStack { ViewFactory.button("back_icon", renderingMode: .template) .foregroundColor(.orange) .background( GeometryReader { geometry in Circle() .offset(x: 2.5) .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) Spacer() ... }
في مقتطف الشفرة أعلاه ، حددنا الزر الأول من عرض الشريط. إليك ما يجري:
- ViewFactory.button - نحن هنا نستخدم طريقة المساعد الخاصة بنا لتعريف الزر مع الصورة باستخدام renderingMode .template الذي يسمح لك بوضع لون مخصص لهذه الصورة
- .foregroundColor - تحديد لون وجهة نظرنا
- .background - تحدد هذه الطريقة طريقة عرض خلفية الكائن المحدد
- GeometryReader - طريقة عرض حاوية تعرّف محتواها كدالة بحجمها الخاص وتنسيق المسافة. نحن نستخدم هذا للحصول على الحجم الحالي للزر وتحديد دائرة الخلفية بالإطار المحدد. تعلم المزيد عن القراء الهندسة هنا .
- الدائرة - يحدد شكل الخلفية
- .offset - دائرة إزاحة المحور السيني
- .foregroundColor - لون دائرة اللون
- . الظل - دائرة الظل
- .frame - يحدد إطار الدائرة باستخدام حجم قارئ الهندسة (هنا نعرّف دائرة خلفية ، أكبر بمقدار 1.5 مرة من الزر الحالي)
الآن دعونا ننفذ بقية الأزرار:
struct BottomBarView: View { var body: some View { HStack { ViewFactory.button("back_icon", renderingMode: .template) .foregroundColor(.orange) .background( GeometryReader { geometry in Circle() .offset(x: 2.5) .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) Spacer() ViewFactory.button("close_icon", renderingMode: .template) .foregroundColor(.red) .background( GeometryReader { geometry in Circle().foregroundColor(.white) .frame(width: geometry.size.width * 2, height: geometry.size.height * 2) .shadow(color: .gray, radius: 12) } ) Spacer() ViewFactory.button("approve_icon", renderingMode: .template) .foregroundColor(.green) .background( GeometryReader { geometry in Circle() .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 2, height: geometry.size.height * 2) } ) Spacer() ViewFactory.button("boost_icon", renderingMode: .template) .foregroundColor(.purple) .background( GeometryReader { geometry in Circle() .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) } .padding([.leading, .trailing]) } }
ونتيجة لذلك لدينا الآن هذا الرأي الجميل:
SwipeView
هذا القسم مخصص لمزيد من SwiftUI. هذا هو حقا حيث تصبح الأمور مثيرة للاهتمام. نود أن ننفذ لفتة التمرير على عرض العمل. يعتبر هذا السلوك حالة استخدام لطيفة لـ PageViewController ، ولكن سيكون جهاز التحكم في العرض هذا محفوظًا قريبًا ، لذلك يمكننا إظهار القوة الحقيقية لـ SwiftUI.
لذلك دعونا نرى كيف يتم تطبيق SwipeView:
struct SwipeView: View { @State private var offset: CGFloat = 0 @State private var index = 0 let users = [...] let spacing: CGFloat = 10 var body: some View { GeometryReader { geometry in return ScrollView(.horizontal, showsIndicators: true) { HStack(spacing: self.spacing) { ForEach(self.users) { user in UserView(userModel: user) .frame(width: geometry.size.width) } } } .content.offset(x: self.offset) .frame(width: geometry.size.width, alignment: .leading) .gesture( DragGesture() .onChanged({ value in self.offset = value.translation.width - geometry.size.width * CGFloat(self.index) }) .onEnded({ value in if -value.predictedEndTranslation.width > geometry.size.width / 2, self.index < self.users.count - 1 { self.index += 1 } if value.predictedEndTranslation.width > geometry.size.width / 2, self.index > 0 { self.index -= 1 } withAnimation { self.offset = -(geometry.size.width + self.spacing) * CGFloat(self.index) } }) ) } } }
استخدمنا هنا بعض مفاهيم SwiftUI الجديدة والمثيرة للاهتمام:
- @ State - قيمة ثابتة لنوع معين ، من خلالها تقرأ طريقة العرض القيمة وتراقبها ، مما يعني أنه كلما تغيرت هذه الخاصية ، سيتم إعادة تحميل العرض لضبط تحديث الحالة المحدد. يمكنك التحقق من المزيد عن الدولة هنا .
- DragGesture - سيتم استخدام هذا الكائن للتعرف على كل انتقاد يقوم به المستخدم على الشاشة. يمكنك قراءة المزيد حول هذا الموضوع هنا: developer.apple.com/documentation/swiftui/draggesture
- @ State var offset: CGFloat = 0 - سيتم استخدام هذه الخاصية لتحديد إزاحة عرض التمرير الحالية عندما ينتقل المستخدمون على الشاشة
- @ State private index var = 0 - تحدد هذه الخاصية طريقة عرض المستخدم الموجودة حاليًا على الشاشة
- ScrollView - عرض التمرير الأفقي بدون مؤشرات ، والتي ستكون حاوية لعرض المستخدم لدينا
- HStack - عرض مكدس أفقي يحتوي على جميع طرق عرض المستخدم
- content.offset (self.offset) - يقوم بإنشاء اتصال بين حالة الإزاحة وإزاحة محتوى عرض التنقل. هذا يعني أنه كلما تغيرت خاصية الإزاحة ، سيتم أيضًا تحديث إزاحة عرض التمرير
نحن نعدد المستخدمين الحاليين عن طريق إنشاء
UserView لكل عنصر:
- .frame - هنا نحدد إطار عرض التمرير الذي يجب أن يتناسب مع عرض الشاشة ، ويجب محاذاته بشكل صحيح مع الحاوية الخاصة به
- .esture - هنا نضيف كائن DragGesture الخاص بنا
DragGesture معقد بعض الشيء ، لكن مع ذلك ، فإنه يضيف كل منطق ترقيم الصفحات في بضعة أسطر من التعليمات البرمجية. دعنا
ننهار DragGesture :
- onChanged () - يتم استدعاء هذا الحظر كلما بدأ المستخدم في وقت سحب الإيماءة ، وهنا نقوم بحساب إزاحة عرض المستخدم الحالي الذي يتبع إصبع المستخدمين
- onEnded () - هنا يتم إعلامنا عند انتهاء إيماءة السحب ، وهنا نحتاج إلى حساب ما إذا كان المستخدم يرغب في تمرير هذا العرض (يسار أو يمين) ، أو ربما تم وضع علامة على هذه الإيماءة ، ويرغب المستخدم في البقاء على هذه الشاشة
- withAnimation - يتم الاحتفال بهذا الإغلاق مع الرسوم المتحركة ، ويسمح بتغيير الإزاحة بشكل متجانس
ContentView
struct ContentView: View { var body: some View { VStack { NavigationView() .padding(.bottom) SwipeView() .padding(.bottom) BottomBarView() } .padding() } }
طريقة العرض الخاصة بالمحتوى لدينا بسيطة للغاية في هذه المرحلة - فهي تؤلف جميع المشاهدات التي أنشأناها مسبقًا ، داخل رصة عمودية (
VStack ). بالنسبة إلى
NavigationView و
SwipeView ، أضفنا بعض
الحشوات الافتراضية في الأسفل ، وكل
VStack يحتوي على
وسادات مضافة إلى جميع الحواف.
هذا كل شيء. القيام به. هذه هي الطريقة التي يبدو بها تطبيقنا الآن:
الأفكار النهائية
كما يمكننا أن نرى SwiftUI هي أداة قوية للغاية ، فهي توفر لنا طريقة سهلة لتعريف واجهة المستخدم ومعالجتها برمز تعريف قصير. يمكن لمطوري
Reactative الأصليين التعرف على هذا النموذج التعريفي على الفور.
ولكن تذكر: SwiftUI لا يزال قيد التطوير ويمكن أن يكون غير مستقر للغاية في الوقت الحالي. إذا كنت ترغب في التحقق من جميع القواعد البرمجية لهذا المشروع ، يمكنك العثور عليها على
جيثب .
إذا كانت لديك أية أفكار أو أسئلة حول SwiftUI ، فلا تتردد في مشاركتها في التعليقات. أيضًا ، إذا كنت قد استمتعت بهذا المقال ، فيرجى مشاركته مع مجتمعك لمساعدتنا في نشر الكلمة!