Introduction to Dynamic Collection Views in SwiftUI

(أ) استخدام أجهزة الإيوسفير الحديثة لسائل الطلب، والوصلات البينية التكييفية التي تستجيب بشكل معقول لمختلف أحجام البيانات، والتوجهات نحو الأجهزة، والأبعاد الشاشة.() وفي UIKit، توفر آراء جمع المعلومات آلية قوية ولكن حقيقية لبناء مخططات شبيهة بالشبكة.() وتبسط هذه العوامل بشكل كبير مع مؤشراتها المتطورة، ولا سيما من خلال

وتكيف صورة جمع البيانات الديناميكية ] مع عدد الأعمدة، أو طول الصف، أو المباعدة، أو تصعيد السلوك على أساس عرض الحاويات المتاحة، أو عدد الأصناف، أو المحتوى نفسه، وتسترشد هذه المادة في إعداد هذه المخططات في سويفتول، وتغطي كل شيء من تركيب الشبكة الأساسية لسلوكيات التكيف المتقدمة، والآراء النهائية للأداء، والتكامل مع ذلك.

العناصر الأساسية: لازيفريد ولازيه غريد

ويوفر موقع سويفتو حاويتين أساسيتين للشبكة: LazyVGrid] (شبكة التموين الفاسد) و]LazyHGrid) (شبكة للتشغيل الأفقي) وكلتا الحملتين اللتان يحملان أطفالهما، ويعني ذلك أن الآراء لا تُنشأ إلا بعد ظهورها على شاشة.

Grid Item Configuration

ولتعريف هيكل الشبكة، تخلق مجموعة من الحالات Grid Item]، وكل ] تمثل عمودا واحدا (في ) أو صفا واحدا (في ]).

  • Size] — one of three sizing modes: , ], or .
  • Spacing] — Horizontal spacing between items in the same row (for capital grids) or column spacing (for horizontal grids).
  • Alignment] - Controls how items align within a grid cell. Rarely changed from defaults.

ويحدد اختيار طريقة التوسيع المرونة العامة في التصميم:

  • Fixed] – Explicit width (or altitude) for every column/row. Useful when you need exact sizing, e.g., a three‐column layout of fixed 100-point cells.
  • Flexible] - يمكن أن تمتد كل صنف من بنود الشبكة لملء الحيز المتاح، بالحد الأدنى والحد الأقصى الاختياري، وهذا هو الخيار الأكثر شيوعاً للأعمدة الدينامية والمنحرفة.
  • Adaptive] - تحدد الشبكة تلقائياً عدد الأصناف التي تناسب كل صف عمودي استناداً إلى حد أدنى محدد، وهذا هو أبسط وسيلة لوضع مخطط دينامي يستجيب للاستعارة الشاشة.

على سبيل المثال، لخلق شبكة تلائم أكبر عدد ممكن من الأعمدة، كل واحد منها لديه أدنى عرض من 100 نقطة، ستكتب:

let columns = [
 GridItem(.adaptive(minimum: 100))
]

هذا الخط الوحيد يُنتج مخططاً يُكيف من عمود واحد على أيفون ضيق إلى عدة أعمدة على أيباد في المشهد الطبيعي بالضبط السلوك الذي نريده للتصميمات الدينامية

بناء ظبّة ديناميكية أساسية

فلنبدأ بشبكة بسيطة ودينامية تماما باستخدام ] مضغوطة، ويتضح من ذلك أن هناك رؤية كاملة تبين مجموعة من الخيوط في شبكة مستجيبة:

struct AdaptiveGridView: View {
 let items = Array(1...20).map { "Item \($0)" }

 var body: some View {
 ScrollView {
 LazyVGrid(
 columns: [GridItem(.adaptive(minimum: 80), spacing: 12)],
 spacing: 12
 ) {
 ForEach(items, id: \.self) { item in
 Text(item)
 .frame(minWidth: 80, maxWidth: .infinity, minHeight: 80)
 .background(Color.blue.opacity(0.2))
 .cornerRadius(8)
 }
 }
 .padding()
 }
 }
}

وهنا، يُجبر كل بند على 80 نقطة على الأقل على نطاق واسع وطويل، ثم يحسب البند الشبكي تلقائياً عدد الأصناف التي يمكن أن تناسب كل صف، بالنظر إلى البارود المتاح، مع احترام الحد الأدنى من الأسلاك، ونتيجة لذلك مخطط يُعاد تدفقه ببطئ عندما يتناوب الجهاز أو يعاد تشكيل النافذة (على أيباد أو ماك).

This approach works well for simple content, but for more control you often need to combine with items, or use to compute custom column counts.

استخدام جهاز قياس الأرضي للكونتات الديناميكية

While ] handles many cases, sometimes you want to set an exact number of columns based on the container width — for example, always 2 columns on an iPhone in portrait, 3 in landscape, and 4 on iPad. The Geometry Reader column provides the current size of its parent, enabling you to calally cald.

مثال: كونت كولوم إيجابي

وفيما يلي نص الرأي المستعار المتاح، ويحسب العمود استنادا إلى عرض مستهدف:

struct DynamicColumnGridView: View {
 let items = Array(1...30).map { "Item \($0)" }
 let targetItemWidth: CGFloat = 120

 var columns: [GridItem] {
 let count = max(Int(geometryProxy.size.width / targetItemWidth), 1)
 return Array(repeating: GridItem(.flexible(), spacing: 12), count: count)
 }

 var body: some View {
 GeometryReader { geometry in
 ScrollView {
 let width = geometry.size.width
 let count = max(Int(width / targetItemWidth), 1)
 let columns = Array(repeating: GridItem(.flexible(), spacing: 12), count: count)

 LazyVGrid(columns: columns, spacing: 12) {
 ForEach(items, id: \.self) { item in
 Text(item)
 .frame(minWidth: 0, maxWidth: .infinity, minHeight: 80)
 .background(Color.green.opacity(0.3))
 .cornerRadius(8)
 }
 }
 .padding()
 }
 }
 }
}

Important:] In practice, you must store the ] value inside a change or use it within the same closure. The above example uses a helper change inside the closure for clarity. always ensure you don’t wrap the entire body in unnecessarily -- it can break the laymo view if used as top.

هذه التقنية تعطيك السيطرة الكاملة على عدد الأعمدة بينما تحافظ على المواد المرنة حتى تملأ الباروكة بشكل متساو، ويمكنك أيضاً إضافة الحد الأدنى والحد الأقصى للبنود المرنة لتجنب الزنزانات الممتدة أو المحطمة.

تكييف مرتفعات الروم ديناميكيا

كما أن مخططات الديناميكية ليست مجرد عن الأعمدة - بل يمكن أن تتباين مستوياتها أيضا على أساس المحتوى، ولا توفر شبكة " الصبغة الاصطناعية " المباشرة مثل شبكة UIKit التي تحتوي على أحجام مقدرة، ولكن يمكن أن تحقق نتائج مماثلة باستخدام حجم المحتوى المتأصل و أو بتوليد مستويات عالية من البيانات.

وعلى سبيل المثال، يمكن أن تجعل كل خلية من الخلايا ذاتية عن طريق إغفال ارتفاعات واضحة والسماح للمحتوى الداخلي بتحديد الحجم.

معالجة مجموعات البيانات الكبيرة مع اللواد الكسولة

ومن المزايا الرئيسية لـ و سلوكهم في التحميل الكسول، فهي لا تخلق سوى آراء بشأن البنود التي تظهر حاليا (بالإضافة إلى حاجز صغير)، مما يجعلها فعالة بالنسبة لمجموعات البيانات التي تحتوي على مئات أو حتى آلاف الأصناف، غير أن هناك بضع ممارسات أفضل للمحافظة على الأداء السلس:

  • Use stable identifiers] — always provide a unique ] parameter to . For struct data models that conform to , SwiftUI can diff efficiently.
  • تجنب الحساب الباهظ التكلفة داخل الجسم ] - إبقاء آراء الخلايا بسيطة، إذا كنت بحاجة إلى حسابات تخطيط معقدة،
  • Leverage ] - إذا كان رأيك الخلوي يتفق مع ] أو يستخدم تعديلا، يمكن أن يفوت الوحدة التغييرات عندما لا تتغير بيانات الخلية.
  • Use ] inside a — if you nest a ] inside another lazy container, you may break lazy loading.

الجمع بين العيون الديناميكية والتقديرات

ويمكن أن تؤدي الصور في سويفتو إلى تغيير التصميم إلى تغيير طبيعي ومهبل، مثلاً عندما يتغير عدد الأعمدة (التي تُجرى للتناوب أو إعادة تثبيت النوافذ)، يمكن أن تُقلل المواد الشبكية إلى مواقعها الجديدة، ويُسهل أن تُغل الشبكة في ]]، مع تعديل أو استخدام ، مع تغيير قيمة.

Animating Column Changes

وهنا تمدد العمود الدينامي السابق مع انتقال محاكا:

struct AnimatedDynamicGridView: View {
 let items = Array(1...20).map { "Item \($0)" }
 @State private var targetItemWidth: CGFloat = 120

 var body: some View {
 GeometryReader { geometry in
 ScrollView {
 let width = geometry.size.width
 let count = max(Int(width / targetItemWidth), 1)
 let columns = Array(repeating: GridItem(.flexible(), spacing: 12), count: count)

 LazyVGrid(columns: columns, spacing: 12) {
 ForEach(items, id: \.self) { item in
 Text(item)
 .frame(minWidth: 0, maxWidth: .infinity, minHeight: 80)
 .background(Color.orange.opacity(0.4))
 .cornerRadius(8)
 .transition(.scale.combined(with: .opacity))
 }
 }
 .padding()
 .animation(.spring(response: 0.4, dampingFraction: 0.7), value: count)
 }
 }
 }
}

وبربط المقياس بالقيمة ]، سيُنقِّي سويفتوي إدخال الأصناف وإزالتها وإعادة ترتيبها عندما يتغير عدد الأعمدة، ويمكنك أيضاً استخدام في عمليات الانتقال الأكثر تقدماً بين المخططات.

أمثلة عملية: العيون الدينامية العالمية الحقيقية

فلنمشي عبر سيناريوهين مشتركين يستفيدان من مخططات النظر الدينامية في مجال جمع الآراء.

معرض الصور

(أ) نظام مُتَحدّد للتصوير يستخدم شبكة خلية مربعة تتكيف مع عرض الشاشة، تريد أن تكون الخلايا كبيرة قدر الإمكان، بينما تحتفظ بعدد ثابت من الأعمدة (مثلاً، 2 على أيفون، 3 على إيفون زائد، 4 على إيباد) باستخدام مع العمود المشروط الذي يستند إلى فئات الحجم هو مستقيم:

struct PhotoGalleryGrid: View {
 let images: [String]

 @Environment(\.horizontalSizeClass) var sizeClass

 var columns: [GridItem] {
 let count = sizeClass == .compact ? 2 : 4
 return Array(repeating: GridItem(.flexible(), spacing: 2), count: count)
 }

 var body: some View {
 ScrollView {
 LazyVGrid(columns: columns, spacing: 2) {
 ForEach(images, id: \.self) { imageName in
 Image(imageName)
 .resizable()
 .aspectRatio(1, contentMode: .fill)
 .clipped()
 }
 }
 .padding(.horizontal, 2)
 }
 }
}

لوحة ديناميك مع مقاس خلية فارغيد

بالنسبة لوح مظلات، قد يكون لديك خلايا من مختلف الواسير - مثل رسم بياني كبير يتناول عمودين، وإحصاءات أصغر حجماً تأخذ عموداً واحداً، ويمكنك تحقيق ذلك عن طريق الجمع بين أصناف مع مضاعفات واضحة تستخدم صفيفة .

let columns: [GridItem] = [
 GridItem(.flexible(minimum: 80), spacing: 12), // small stat cell
 GridItem(.flexible(minimum: 160), spacing: 12), // wide cell
 GridItem(.flexible(minimum: 80), spacing: 12) // small stat cell
]

ثم في الشبكة ، يمكنك أن ترسم خرائط لمختلف أنواع البيانات إلى عمود مختلف عن طريق تغليف المواد في حاوية توسع لملء البارود الشبكي، وهذا يتطلب تنسيقا دقيقا لأن ] لا يدعم محلياً ما بين عدة مواضع، ومن المعالم العامة استخدام [FLT: manual split]

وفيما يتعلق بالمحطة 16، وبعد ذلك، يمكن استخدام ] تعديل وجهة نظر داخل الشبكة لتحديد عدد الأعمدة التي ينبغي أن تشملها هذه النظر:

LazyVGrid(columns: columns, spacing: 12) {
 ForEach(dashboardItems, id: \.id) { item in
 DashboardCell(item: item)
 .gridCellColumns(item.columnSpan)
 }
}

هذه هي أنظف طريقة لخلق مخطط ديناميكي حقيقي مع أحجام خلايا مختلطة

اعتبارات الأداء بالنسبة لمجموعة البيانات الكبيرة

عندما تتعامل مع آلاف الأشياء، حتى التحميل الكسول يمكن أن يؤدي إلى الخناق إذا كانت كل خلية معقدة، هنا تقنيات متقدمة لإبقاء شبكاتك الدينامية سلسة:

  • Prefetch images and data] - Use or to load data asynchronously, not in the cell’s body.
  • Use for extremely large lists] – SwiftUI’s is more optimized for thousands of rows with dynamic sizing. However, for a grid layout, with a custom layout is possible but hard to achieve; consider using [FL57]
  • ][Limit re computation of layout - Avoid putting dynamic layout logical inside the cell’s body. Precompute geometries when possible.
  • Use on the entire grid] — if you completely change the grid structure (e.g., shifting from 2 columns to 3), assigning a new to the grid forced it to reload entirely, which can be faster than trying to animate a complex change.

الموارد الخارجية لعمق معرفتك

To further explore dynamic collection views in SwiftUI, refer to these official and community resources:

  1. Apple’s LazyVGrid Documentation - The official reference for all parameters and behaviors. ] Apple Developer Documentation: LazyVGrid]
  2. Quick Start Guide for Grid Item] - Covers all three sizing strategies with interactive examples. ] Apple Developer Documentation: Grid Item]
  3. SwiftUI by Example – Grid Layouts] — A practical tutorial from Hacking with Swift that covers adaptive and flexible grids. ] Hacking with Swift: Grid Layouts
  4. SwiftUI Lab: Lazy Grids] - Deep dive into performance and customizations. ] SwiftUI Lab: Lazy Grids

موجز أفضل الممارسات

ويتطلب إنشاء نظام ديناميكي لطرح وجهات النظر في نظام سويفتول تحقيق التوازن بين المرونة والأداء، وهذه قائمة مرجعية سريعة لشبكات الإنتاج - الخيوط:

  • ابدأ بـ ] لـ أبسط إحصاء ديناميكي؛ استخدام فقط عندما تحتاج إلى رقابة دقيقة.
  • (د) دائماً توفر قيماً فريدة أو تتفق مع .
  • Use with a value that changes (like column count) to smooth transitions.
  • For mixed cell sizes, prefer on iOS 16+ or design a custom row‐by---row layout.
  • تُظهر شبكتك بالأدوات للتحقق من التحميل الكسول يعمل والزنزانات لا تُظهر محتوىً غير مُستشف
  • اختبارات على أحجام متعددة الأجهزة وتوجهاتها - مخططات دينامية تبدو رائعة على شاشة واحدة قد تكسر على شاشة أخرى.

إن استخلاص آراء دينامية في مجال جمع الآراء يمكّنك من بناء تطبيقات تشعر بالوطن وتجاوبها في كل جهاز من أجهزة التفاح، وبأدوات التفاضلية التي وضعها سويفتو، يمكنك تحقيق ما كان يتطلبه في وقت ما عشرات خطوط من رموز نظام UIKit في حفنة من المكونات الصريحة والمتجددة.