Table of Contents
ويشكل بناء مقاصة إخبارية دينامية سمة أساسية بالنسبة لتطبيقات iOS التي لا تحصى، من جانب عملاء وسائط التواصل الاجتماعي إلى محتوى المجمّعين والأجهزة الإخبارية المهنية، وفي مجال تطوير نظام المعلومات البيئية، و، تشكل الحاويتان الرئيسيتان القابلتان للتصميم لعرض مجموعات البيانات، بينما تتقاسمان العديد من أوجه التشابه - تعتمد على الوفود ومصادر البيانات، والخلايا المثلى القابلة للتعديل.
Understanding UITableView and UICollectionView
وقبل أن يتم التنفيذ، من الأهمية بمكان فهم الاختلافات المعمارية ومتى تختار واحدة على الأخرى، وكلاهما جزء من نظام UIKit ويتبع نمط MVC (Model-View-Controller) ولكن قدراتهما على التصميم وأجهزة التنفيذ المدمجة تتباين بشكل كبير.
UITableView: The Workhorse for Lists
presents a single column of rows that can be grouped into sections. Each row corresponds to a cell, and the view automatically manages capital scrolling, cell reuse, and row animations. It is the natural choice for newsfeed where each item is a consistent, Verdely stacked layout: a headline, a brief description, a timestamp, and optionally an image.
UICollectionView: Flexibility for Complex Layouts
(ه) يفصل عرض البيانات عن الخوارزمية المصممة عن طريق الجسم، ويرتب التدفق الافتراضي () مواد في شبكة أو خطوط أفقية/فضائية، ولكن يمكنك أن تصنفه أو تستخدمه في شكل بيانات أفقية متعددة الجوانب (ي)
إعداد الأخبار الأساسية
سنسير من خلال إنشاء جهاز مراقبة للمشاهدات على الأقل من المشاهدات المزودة بالأخبار لكل عنصر، ويفترض كلا المثالين أنكم تبنيون برنامج واحد للشاشات مع (إكسيد) و(سويفت)
إنشاء صحيفة جديدة مع شركة UITableView
(أ) البدء من خلال تصنيف فرعي ومطابقة و.
import UIKit
class NewsTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let tableView = UITableView()
private let newsItems: [String] = [
"Breaking: Major Policy Change Announced",
"Tech Giants Unveil AI Partnership",
"Local Weather Warning: Heavy Rain Expected"
]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "News Feed"
setupTableView()
}
private func setupTableView() {
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.rowHeight = 80
view.addSubview(tableView)
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newsItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = newsItems[indexPath.row]
cell.textLabel?.numberOfLines = 0
cell.accessoryType = .disclosureIndicator
return cell
}
// MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: Path) {
tableView.deselectRow(at: indexPath, animated: true)
// Navigate to article detail (to be implemented)
}
}
وفي هذه النسخة الأساسية، تعرض كل خلية خطاً واحداً من النصوص، أما بالنسبة لبث أخبار الإنتاج، فستحل محل البسيط مع تصنيف فرعي مصنف حسب الطلب يحتوي على بطاقات لقب ووصف وصورة، ويوصى باستخدام ] للطول الدينامي عندما تختلف طول المحتوى.
إنشاء نشرة إخبارية مع شركة UICollectionView
وبالنسبة لبث شبكي متطور (في شكل بطاقات إخبارية متحركة) ننفذ باستخدام .
import UIKit
class NewsCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private var collectionView: UICollectionView!
private let imageNames = ["news1", "news2", "news3", "news4"] // Assume images in asset catalog
override func viewDidLoad() {
super.viewDidLoad()
title = "Image Feed"
setupCollectionView()
}
private func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumInteritemSpacing = 8
layout.minimumLineSpacing = 8
layout.sectionInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")
view.addSubview(collectionView)
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCell
cell.loadImage(named: imageNames[indexPath.item])
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 8 * 3 // 3 gaps: left, interitem, right
let availableWidth = view.frame.width - padding
let widthPerItem = availableWidth / 2
return CGSize(width: widthPerItem, height: widthPerItem * 1.2)
}
}
// Custom cell class
class ImageCell: UICollectionViewCell {
private let imageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
required init?(coder: NSCoder) { fatalError("init(coder:)") }
func loadImage(named: String) {
imageView.image = UIImage(named: named)
}
}
This code creates a two —column grid with a 1.2:1 aspect ratio per cell. You can adjust to for a carousel —style feed. For real apps, replace place placeholder images with asynchronous image loading via or library like Kingfisher]
خلايا تعارف لـ "ريتشر نيوزفيد"
خلايا النص غير كافية لتطبيق الأخبار الحديثة، تحتاج إلى عرض الإبهام، ومواعيد النشر، وأسماء المصدر، وأحياناً أزرار تفاعلية (التقاسم، الادخار)، وهذا يتطلب خلق العرف أو مع استعراضات فرعية مصاغة على النحو المناسب.
تصميم خلية مواد مسمّاة (UITableView)
Create a cell that includes a for a large hero image, a for the headline, another for the excerpt, and a small label for the timestamp. Use Auto Layout to ensure the cell expands correctly. Example:
class ArticleCell: UITableViewCell {
let heroImageView = UIImageView()
let titleLabel = UILabel()
let excerptLabel = UILabel()
let dateLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) { fatalError() }
private func setupViews() {
heroImageView.contentMode = .scaleAspectFill
heroImageView.clipsToBounds = true
titleLabel.font = UIFont.boldSystemFont(ofSize: 18)
titleLabel.numberOfLines = 2
excerptLabel.font = UIFont.systemFont(ofSize: 14)
excerptLabel.textColor = .gray
excerptLabel.numberOfLines = 3
dateLabel.font = UIFont.systemFont(ofSize: 12)
dateLabel.textColor = .lightGray
for subview in [heroImageView, titleLabel, excerptLabel, dateLabel] {
subview.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(subview)
}
// Constraints – simplified; in practice use stack views or manual anchors
NSLayoutConstraint.activate([
heroImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
heroImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
heroImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
heroImageView.heightAnchor.constraint(equalToConstant: 200),
titleLabel.topAnchor.constraint(equalTo: heroImageView.bottomAnchor, constant: 8),
titleLabel.leadingAnchor.constraint(equalTo: heroImageView.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: heroImageView.trailingAnchor),
excerptLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
excerptLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
excerptLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
dateLabel.topAnchor.constraint(equalTo: excerptLabel.bottomAnchor, constant: 4),
dateLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
dateLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
])
}
func configure(with article: Article) {
titleLabel.text = article.title
excerptLabel.text = article.excerpt
dateLabel.text = article.dateString
// Load image asynchronously (omitted)
}
}
In the view controller, register this custom cell and implement accordingly. Set and to allow changing altitudes.
تكييف الخلية لـ (أوكفولك فيو)
وينطبق نفس النمط على . ونظراً لأن آراء جمع البيانات يمكن أن تكون لها مخططات مختلفة، فقد تصمم خلية " مقلبية " تعمل في كل من أساليب التكسير الرأسية والأفقية.
class NewsCardCell: UICollectionViewCell {
private let cardView = UIView()
private let imageView = UIImageView()
private let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 10
cardView.clipsToBounds = true
cardView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(cardView)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
titleLabel.numberOfLines = 2
titleLabel.translatesAutoresizingMaskIntoConstraints = false
cardView.addSubview(imageView)
cardView.addSubview(titleLabel)
// Layout
NSLayoutConstraint.activate([
cardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4),
cardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4),
cardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4),
cardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4),
imageView.topAnchor.constraint(equalTo: cardView.topAnchor),
imageView.leadingAnchor.constraint(equalTo: cardView.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: cardView.trailingAnchor),
imageView.heightAnchor.constraint(equalToConstant: 120),
titleLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 8),
titleLabel.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 8),
titleLabel.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -8),
titleLabel.bottomAnchor.constraint(lessThanOrEqualTo: cardView.bottomAnchor, constant: -8)
])
}
required init?(coder: NSCoder) { fatalError() }
}
بهذه الزنزانة، يمكن أن تظهر صورة من نوع بينتريس لو قدمتم أحجاماً مختلفة من خلال المندوب
إضافة مستجدات في الوقت الحاضر
ويجب أن تدعم المقذوفات الإخبارية الحديثة لفتات جديدة وتحميل ديناميكي.() وتدمج صف ] بغموض مع كل من و عندما يكون النظرة الملتوية متصلا بالفعل بضبط جديد.() في :
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshNewsFeed), for: .valueChanged)
tableView.refreshControl = refreshControl
// or collectionView.refreshControl = refreshControl
In the method, perform asynchronous data fetch (e.g., from a REST API), then reload the view on the main queue and call . Example:
@objc private func refreshNewsFeed() {
NewsAPIClient.fetchLatestArticles { [weak self] articles in
DispatchQueue.main.async {
self?.newsItems = articles
self?.tableView.reloadData()
self?.tableView.refreshControl?.endRefreshing()
}
}
}
وللاستكمالات في الوقت الحقيقي مثل الأخبار العاجلة الحية، النظر في استخدام أو مكتبة طرف ثالث مثل قاعدة بيانات " قاعدة بيانات " فرايت " ، عند وصول بيانات جديدة، تدرج صفوف أو بنوداً ذات أهداف:
// For UITableView
tableView.performBatchUpdates({
tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .top)
}, completion: nil)
// For UICollectionView
collectionView.performBatchUpdates({
collectionView.insertItems(at: [IndexPath(item: 0, section: 0)])
}, completion: nil)
معاملات المستخدمين والملاحة
وعندما يستعمل المستخدم مادة إخبارية، ينبغي أن ينتقل التطبيق إلى نظرة مفصلة، وتنفيذ طريقة المندوبين، واستخدام إما مسلسل للوحات أو دفعة برنامجية، وفيما يتعلق بكل من الجداول والمجاميع، فإن طريقة المندوبين توفر مساراً للأرقام القياسية.
// In UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let article = newsItems[indexPath.row]
let detailVC = ArticleDetailViewController(article: article)
navigationController?.pushViewController(detailVC, animated: true)
}
// In UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let article = newsItems[indexPath.item]
let detailVC = ArticleDetailViewController(article: article)
navigationController?.pushViewController(detailVC, animated: true)
}
النظر في إضافة إشارات طويلة إلى أعمال إضافية (بالتقاسم، علامة الكتاب) عن طريق مرفقة بنظرة جمع أو طاولة، أو استخدام مقاس السياق الذي أُدخل في المعيار 13 من قواعد البيانات.
اعتبارات الأداء بالنسبة للأطعمة الكبيرة
يمكن أن تنمو الصحف إلى مئات أو آلاف المواد، وكل من و] إعادة استخدام الخلايا للحفاظ على الذاكرة منخفضة، ولكن يجب أن تتجنب منع الخيوط الرئيسي.
- Asynchronous image loading:] never load images from the network on the main queue. Use Library like ]Kingfisher or SDWebImage that handle caching, prefetching, automatically.
- Prefetching:] Conform to or to begin loading data for offscreen cells before they appear.
- ] تصفية الأحجام بكفاءة: ] For changing —height cells, use Auto Layout with . In collection views, cache computed sizes to avoid repeated layout calculations.
- لترهيب إصدار خلايا غير مرئية: ] Override in custom cells to abolish image downloads and reset state.
- Usese diffable data sources] (انظر الفرع التالي) لخفض عمليات إعادة تحميل المكالمات وإجراء تحديثات محاكاة بأقل قدر من المرونة.
المصدر: البيانات المجمعة والمتفشية
IOS 13 and later introduced two powerful APIs that dramatically streamline complex newsfeeds: and (which also works with ] via ).
UICollectionViewCompositionalLayout
ويتيح هذا المخطط لكم تحديد الأقسام ذات السلوكات المختلفة، على سبيل المثال، قسم لافتات البطولة الذي يهتز أفقياً، وشبكة من الأخبار العاجلة، وقائمة عمودية بأحدث المواد، وكل قسم محدد بـ يحتوي على مجموعات ومواد.
let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) -> NSCollectionLayoutSection? in
switch sectionIndex {
case 0:
// Horizontal carousel
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .absolute(200))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
section.interGroupSpacing = 10
return section
case 1:
// Vertical grid (2 columns)
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .estimated(150))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(150))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
group.interItemSpacing = .fixed(8)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 8
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)
return section
default:
return nil
}
}
collectionView.collectionViewLayout = layout
المصدر
وبدلاً من استخدام الأدلة وإدارة المسارات القياسية، فإن مصادر البيانات القابلة للنشر تسمح لك بتطبيق الصور الملتقطة، وهذا يزيل التناقضات ويبسط التقديرات.
enum Section {
case featured
case latest
}
struct Article: Hashable {
let id: UUID
let title: String
// ...
}
var dataSource: UICollectionViewDiffableDataSource!
// In viewDidLoad:
dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) {
(collectionView, indexPath, article) -> UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ArticleCell
cell.configure(with: article)
return cell
}
// When data arrives:
var snapshot = NSDiffableDataSourceSnapshot()
snapshot.appendSections([.featured, .latest])
snapshot.appendItems(featuredArticles, toSection: .featured)
snapshot.appendItems(latestArticles, toSection: .latest)
dataSource.apply(snapshot, animatingDifferences: true)
ويمكن أيضاً استخدام مصادر بيانات واسعة النطاق مع ] عبر .() وهذا النمط أصبح الآن [يوصي به لجميع المشاريع الجديدة لأنه يزيل الحشرات المشتركة ويبسط إدارة الدولة.
إدماج مصادر البيانات الحقيقية
لجعلكم تُرفّقون الأخبار دينامية، وربطوها بجهاز تسجيل مُسبق، وتشمل النُهج المشتركة ما يلي:
- REST API:] Use ] to fetch JSON, decode it with ], and populate your model array. Example with [iOS 15+):
func fetchArticles() async throws -> [Article] {
let url = URL(string: "https://api.example.com/news")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Article].self, from: data)
}
- Core Data / CloudKit:] For offlinefirst feeds, store articles locally using Core Data, then coincide with a cloud backend. Use an with to automatically update the UI when data changes.
- Firebase Firestore:] Realtime listeners can update the collection view snapshot directly.
دائماً يتعامل مع الأخطاء بشكل جيد كيف يكون مالك مكان أو زر إعادة أو نسخة مخبأة من الطعام
التضاريس المتقدمة والبولندية
لكي تجعلي دفتكِ الإخبارية تبرزين، فكري في التحسينات التالية:
- Animated cell transitions:] Use or the collection view’s method to fade in cells as they appear.
- Context menus and swipe actions:] On , implement to mark articles as read or save them. For , use via the delegate.
- Sticky section headers:] For grouped feeds, make section headers “sticky” by using the plain table view fashion or setting on a compositional layout.
- Dark mode and dynamic type:] Use and to ensure your feed respects system settings.
اختبار نشرة أخبارك
برمجة اختبارات وحدة البيانات الخاصة بمنطق مصدر البيانات واختبارات الطلقات الضوئية للتراجع البصري، استخدم جهاز التبسيط لاختبار مختلف أحجام الأجهزة وتوجهاتها، لاختبار الأداء، أداة مع مُحددة للزمن، وتحقق من الأُطر المُسقطة أثناء التكسير.
خاتمة
ULT:[FLT]، بالإضافة إلى الأدوات الحديثة مثل مخططات التكوين ومصادر البيانات القابلة للانتشار، يمكن أن تخلق مستعملين للبث المباشر، وذلك باتباع الأنماط المحددة في تصميم الخلايا الجاهزة، وتحميل البيانات غير المتناظرة، والسحب من جديد، وتلقين دقيقاً للأداء.