UIKit: UICollectionView
UICollectionView ile uygulamalarınızda içeriklerinizi aynı “Fotoğraflar” uygulamasında olduğu gibi gösterebilirsiniz.
Merhaba sevgili TurkishKit okuyucuları! 👋 Bugünkü yazımızın konusu, uygulamaların görünümlerinde sıkça kullanılan ve böylece iOS deneyiminin de önemli bir parçası haline gelen UICollectionView elementi. Başlamadan söyleyelim, eğer Kodlayalım kategorimizdeki en yeni yazımızı okumaya henüz fırsatınız olmadıysa onu da okumanızı kesinlikle öneririm! 😉
UICollectionView Nedir?
UICollectionView elementi, uygulamalarınızda sahip olduğunuz içerikleri çeşitli görünümler ile gösterebilmenizi sağlayan bir arayüz elementidir. Özelleştirilebilme olanağı oldukça yüksek olan bu görünüm sayesinde içeriklerinizi istediğiniz herhangi bir biçimde bir sıraya dizebilir ve gösterebilirsiniz; hatta bu özelliğinden dolayı daha iyi inceleyebilmeniz adına birkaç örnek ekledim 🙂
Photos Uygulaması
Örneğin, Photos uygulamasında bir albümü açtığınızda karşınıza çıkan ızgaraya dizili fotoğraf görünümü için aslında UICollectionView elementinin en temel örneklerinden biri diyebiliriz.
App Store
App Store uygulamasında Bugün görünümündeki kart dizilimi de UICollectionView elementinin oldukça havalı bir örneği sayılabilir. 😄
Hepimizin sıkça kullandığı Instagram da UICollectionView görünümünden sıkça yararlanan bir uygulama, mesela Hikayeler kısmındaki kişilerin dizilişi, ekranın tamamını kaplamayan ve yatay olarak akan bir UICollectionView örneği. Bunun yanında bir kişinin profiline girdiğinizde çıkan görseller de bu element için güzel bir örnek:
Tabii ki UICollectionView’ı kullanabileceğiniz alanlar bunlarla sınırlı değil, biraz sonra kodlayacağımız örnek uygulamamızda görebileceğiniz gibi görünümünü dilediğiniz şekilde özelleştirebilirsiniz!
Bir UICollectionView Nelerden Oluşur?
Yukarıdaki örnekler, birbirinden farklı görünmelerine rağmen sizin de fark etmiş olabileceğiniz birkaç ortak noktaya sahip: görünümlerin hepsinde içerikler, belirli bir sıraya dizili hücreler halinde gösteriliyor ve belirli bir şekilde akıyor. İşte bu ortak noktalar, aslında bir UICollectionView görünümünün oluşmasını sağlayan parçalar: UICollectionViewCell ve UICollectionViewLayout.
UICollectionViewCell
Bir UICollectionView içerisindeki hücrelerin her biri bir UICollectionViewCell olarak adlandırılıyor, ve bir UICollectionView’ın içeriği bu hücrelerin bir araya gelmesiyle oluşuyor. Bahsettiğimiz gibi en güzel kısmı ise, hücrelerin görünümünü istediğimiz şekilde değiştirebiliyor olmanız, yani oluşturabilecekleriniz sadece hayal gücünüzle sınırlı!
UICollectionViewLayout
Tabii ki bir UICollectionView sadece hücrelerin içeriğinden oluşmuyor, aynı zamanda hücrelerin düzeninin ve akış şeklinin de belirlenmesi gerekiyor. Bunun için ise, görevi tam da bunları düzenlemek olan UICollectionViewLayout sınıfı kullanılıyor. Siz de akış düzeniniz için Apple’ın varsayılan olarak sağladığı akış düzenini kullanabilir, veya Cover Flow gibi daha özel bir akış oluşturmak isterseniz kendi Flow Layout’unuzu yaratabilirsiniz.
UICollectionView
Ve bütün bu parçaları bir araya getirip uyum içerisinde çalışmalarını sağlayan kahramanımız, UICollectionView’ın kendisi! Onun görevi ise, içindeki hücreleri ve akış düzenini, ona verilen boyutlara göre bir araya getirmek.
Haydi Kodlayalım!
UICollectionView elementi nedir ve nasıl oluşur, öğrendiğimize göre, artık onunla örnek bir uygulama yapmanın vakti geldi! Bugünkü projemizde, App Store’daki Bugün görünümüne benzer bir görünüm ile yeni haberleri gösteren bir uygulama oluşturacağız. Hazırsanız başlayalım! 🚀
Projemizi Planlayalım
Her yazılım projesinde olduğu gibi, bu projede de kodlamaya başlamadan önce ne yapacağımızı planlamak, daha sonra işimizi çok daha kolaylaştıracaktır. 😉
Bu uygulamada amacımız, App Store’daki kartlara benzer bir görünümle haberler göstermek, ve bunun için ilk olarak uygulamamızda en tepedeki başlık kısmını oluşturacak bir Navigation Controller kullanacağız. İçeriğin kendisini göstermek içinse biraz önce tanıdığımız UICollectionView sınıfını kullanacağız.
İçerik Modelimizi Oluşturalım
Uygulamamızın geri kalanını kodlamaya başlamadan önce, uygulamamızda göstereceğimiz içeriklerin yapısını belirlemeliyiz; yani nasıl bir içerik göstereceğimizi düşünüp, sonrasında ise buna uyumlu bir veri modeli oluşturmalıyız. 📝
Uygulamamızın içeriği haberler olacak, bunun içinse bu tür bir içeriğin sahip olacağı özellikleri düşünelim: her haberde bir başlığımız, bir üst başlığımız ve bir görselimiz olmalı. Bu bilgiler bizim için önemli, çünkü veri modelimizi ve Collection View içerisindeki hücrelerimizi onlar ışığında tasarlayacağız.
Hücremizi Tasarlayalım
Hücrelerin görünümünü ben, hücreyi tamamen kaplayan bir arka plan görseli ile hücrenin alt kısmında küçük bir üst başlık ve büyük bir ana başlık olacak şekilde tasarladım. Tabii ki siz, bunları dilediğiniz şekilde değiştirebilir ve daha da güzel tasarımlar oluşturabilirsiniz! ✨
Projemizi Oluşturmaya Başlayalım!
Öncelikle ilk adımımız, her zamanki gibi Xcode üzerinden yeni bir Single View Application projesi oluşturmak olacak. Proje oluştuktan sonra Main.storyboard dosyasını açıyoruz ve karşımıza çıkan boş View Controller ekranına başlık eklemek için View Controller’ı seçerek Xcode üst menüsünden Editor > Embed In ve sonra Navigation Controller seçeneğine tıklıyoruz.
Not: Interface Builder içerisinde arayüzü tasarladığımız cihaz olarak iPhone 11’i seçtim. Bu detay, daha sonra önemli olacak :)
Eklediğimiz başlığı tasarımımızdaki gibi büyük yapmak için Navigation Controller ekranında içi boş olan başlık çubuğuna tıklayıp sağ taraftaki Attributes Inspector menüsünden Prefers Large Titles seçeneğini işaretliyoruz.
Oluşturduğumuz büyük başlığa “Haberler” yazısını eklemek içinse View Controller ekranındaki boş başlığa tıklayıp Attributes Inspector menüsünden başlığımızı yazabiliriz.
En sonunda ise Navigation Controller’ın uygulama çalıştığında gözükmesi için de yine Attributes Inspector menüsünden veya üstüne oku sürükleyerek Initial View Controller haline getiriyoruz.
Uygulamamızın ilk adımı olan başlığı oluşturmak işte bu kadar kolay! ✨
Bu adımlar size bir yerden tanıdık gelmiş olabilir, çünkü daha önceki yazılarımızda da başlık oluşturmak için aynen bu yöntemi kullanmıştık :)
Collection View Elementini Ekleyelim
Başlığımızı oluşturduğumuza göre, artık bir sonraki önemli aşama olan UICollectionView elementini eklemeye ve düzenlemeye geçebiliriz! Aynı zamanda, uygulamamızın her cihazda müthiş görünebilmesi için de Auto Layout kullanacağız. Eğer konuya aşina değilseniz ve daha derinden öğrenmek isterseniz, ilgili yazımıza göz atmaktan çekinmeyin 😉
UICollectionView elementimizi eklemek için Interface Builder’da Library menüsünden Collection View’ı seçiyoruz ve View Controller ekranımızın içine sürükleyip bırakıyoruz.
Eklediğimiz element şu anda ekranın küçük bir kısmını kaplıyor, ancak bu hiç sorun değil: aşağıdaki Add New Constraints butonuna tıklayarak elementimizi ekranın en kenarlarına uzatacak sınırlamalar (constraint) ekliyoruz ve böylece UICollectionView elementimiz ekrandaki bütün alana yayılmış oluyor. Tam da istediğimiz gibi!
UICollectionViewCell Hücresini Oluşturalım
UICollectionView elementimizi de eklediğimize göre hücremizin tasarımını Interface Builder üzerinde oluşturmaya başlayabiliriz. İlk olarak hücrelerimizin boyutunu belirlemek için Collection View üzerinde bir boşluğa tıklayıp Size Inspector menüsünden Cell Size boyutunu Width: 374 | Height: 234 olarak belirleyelim. Bu işlemin sonunda hücremizin büyüdüğünü ve ekranın ortasına yerleştiğini görebilirsiniz. Hücrenin ekranın kenarıyla arasındaki boşluğu ise aynı menüdeki Min Spacing ve Section Insets bölümlerindeki değerleri 16 olarak ayarlayarak düzeltelim.
Bütün bunları yaparken bir yandan Xcode’un oluşturduğumuz hücreye bir isim vermemiz gerektiğine dair bir uyarı verdiğini görmüş olabilirsiniz. Bunu düzeltmek adına ise hücreyi seçip Attributes Inspector menüsünden hücremize bir kimlik (identifier) belirleyerek kod üzerinden kullanıma hazırlamış oluyoruz. Ben hücreye ‘articleCell’ kimliğini verdim, eğer siz de sonraki adımlarda yazacağımız kodları aynen kullanmak istiyorsanız aynı kimliği kullanabilirsiniz.
Şimdi sıra geldi hücremizin içini tasarlamaya! İlk olarak hücremize arka plan resmi olacak UIImageView elementini yerleştirelim. Yerleştirdikten sonra ise Add New Constraints menüsü üzerinden kenarlara olan mesafeyi sıfırlayarak görsel elementimizin bütün hücreyi kaplamasını sağlayalım. Ancak bu sefer constraint’lerimizi eklerken, varsayılan kenar boşluklarından etkilenmemeleri adına Constrain to Margins seçeneğinin işaretini kaldırmayı unutmayalım.
Interface Builder üzerindeki tasarımımızı tamamlamak için artık tek yapmamız gereken, metinlerimizi eklemek! Metinleri eklemeden önce, hücremizin içine onları aşina olduğumuz havalı flu efekti sayesinde arka plandan ayıracak bir Visual Effect View ekleyelim.
Eklediğimiz bu elementi hücrenin alt kısmına yerleştirdikten sonra, onun da içerisine metinlerimizi barındıracak bir Vertical Stack View ekleyelim. Vertical Stack View’ın içerisine ise iki tane Label ekleyelim, ki bu elementler üst başlığımızı ve ana başlığımızı temsil edecek.
Eklediğimiz elementlerin konumlarını daha ayarlamaya başlamadık bile, ancak Stack View şimdiden eklediğimiz Label’ların konumunu bizim için otomatik olarak ayarladı. Şimdi biz de constraint’ler ile konumların geri kalanını ayarlayacağız ve böylece bütün elementlerimizin konumu metinlerin uzunluğuna göre otomatik olarak ayarlanacak!
Not: Constraint’leri eklediğimiz sırada çıkan kırmızı uyarılar sorun değil, çünkü işlemimizi tamamladığımızda hepsi düzelmiş olacak.
En sonunda ise üstteki Label’ımıza gri renk ve küçük bir font, aşağıdakine ise büyük ve kalın bir font verdikten sonra ekran tasarımımız tamamen hazır! 🎉
Veri Modelimizi Kodlayalım
Tasarımını tamamladığımız Collection View elementlerini kodlamadan önce, onların içeriğini oluşturmamızda bize yardımcı olacak veri modelini kodlamamız uygulamayı kodlarken işimizi kolaylaştıracaktır. Daha önce tasarladığımız haber modelini kod haline dönüştüreceğiz, ve bunu gerçekleştirmek için yeni bir Swift yapısı, yani struct, oluşturacağız. 😊
Xcode üzerinde File > New > File.. menüsünden ArticleItem adında yeni bir Swift dosyası oluşturalım. Aynı tasarladığımız haber yapısında olduğu gibi, burada da başlığımızı, üst başlığımızı ve görselimizi saklayacak değişkenlerimiz olacak. Başlık ve üst metin özellikleri metin olduğundan, onları string olarak tanımlayacağız. Görsel değişkenimiz ise iOS platformunda resimleri temsil eden UIImage türünden olacak.
import UIKitstruct ArticleItem {
let image: UIImage
let caption: String
let title: String
}
UICollectionViewCell Hücremizi Kodlayalım
Storyboard dosyamızda yarattığımız özelleştirilmiş hücremizi artık kodlamaya geçebiliriz! Hücremizin kodları için File menüsünden UICollectionViewCell sınıfına ait ArticleCollectionViewCell adında bir Cocoa Touch Class oluşturalım. Bu sınıf, tasarladığımız özel hücreyi kod üzerinde de özelleştirebilmemizi sağlayacak.
Sınıfımızı oluşturduktan sonra, hücrelerimizin tasarımındaki arayüz elemanlarına kod üzerinden erişebilmek için kntrl + sürükle yöntemi ile prototip hücremizdeki UIImageView ve iki UILabel elemanı üzerinden ArticleCollectionViewCell.swift dosyasına IBOutlet oluşturalım.
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var captionLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel!
En sonunda ise, sınıfımızı Interface Builder üzerindeki hücremize bağlamak için Collection View Cell üzerindeki Identity Inspector menüsünden hücremizin sınıfını ArticleCollectionViewCell olarak ayarlayalım.
UICollectionView Elemanlarının İçeriğini Kodlayalım
UICollectionView elemanlarının içeriğini oluşturmak için onları barındıran ekranımızın sınıfı olan ViewController.swift dosyasına geçelim. ViewController sınıfının içerisinde içeriklerimizi barındıracak bir Array değişkeni oluşturuyoruz.
var articles = [ArticleItem]()
Bu değişkeni tanımlarken içindekileri oluşturduğumuz veri modeli olan ArticleItem türünden tanımladık. Sonrasında ise, viewDidLoad metodunda ise bu değişkenin içini içeriklerimiz ile dolduruyoruz.
Sonrasında, viewDidLoad()
metodunda ise bu değişkenin içini içeriklerimiz ile dolduruyoruz.
override func viewDidLoad() {
super.viewDidLoad()
let article1 = ArticleItem(image: #imageLiteral(resourceName: "Her Kız Kodlayabilir"), caption: "TurkishKit Özel Etkinliği", title: "Her Kız Kodlayabilir")
let article2 = ArticleItem(image: #imageLiteral(resourceName: "Sign In with Apple"), caption: "TurkishKit Blog Yazısı", title: "Sign in with Apple")
let article3 = ArticleItem(image: #imageLiteral(resourceName: "Dub Dub '19 Etkinliği"), caption: "TurkishKit Özel Etkinliği", title: "WWDC19 Özel Etkinliği")
articles = [article1, article2, article3]
}
UICollectionView elemanını oluşturmak ve UICollectionViewCell hücrelerinin içini doldurabilmek için ViewController sınıfımızı UICollectionViewDataSource ve UICollectionViewDelegate sınıflarının alt sınıfı olarak tanımlıyoruz.
Bu tanımlamaları yaparken, kodumuzu daha sade ve anlaşılır kılabilmek için Swift dilinin Extension adında bir özelliğinden yararlandık. Bu müthiş özellik sayesinde var olan sınıfların yapabileceklerinin üstüne yeni özellikler ekleyebiliyoruz. 🙌
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
Yukarıdaki kod satırını ekledikten sonra Xcode bir uyarı ile bize bazı metodların eksik olduğundan bahsedecek, biz de Fix butonuna tıklayarak gereken metodları hızlıca ekleyelim 😉
Şimdi ise metodlarımızın içini dolduralım: ilk olarak numberOfItemsInSection metodunu doldurarak Collection View elemanımıza kaç tane hücre oluşturulacağını söyleyeceğiz, ki bu içeriklerimizin sayısına eşit olacak:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return articles.count
}
UICollectionView elementimize kaç hücre olacağını ilettiğimize göre, şimdi hücrelerimizi gerekli içeriklerle dolduracak cellForItemAt metodunu yazabiliriz!
Buradaki kodlar oluşturulan her hücre başına çalıştığı için öncelikle içerik dizimizden o sıradaki makaleyi alıyoruz ve article adında bir değişkene kaydediyoruz. Sonrasında ise, Interface Builder üzerinde belirlediğimiz hücre kimliğine karşılık gelen hücreyi ArticleCollectionViewCell türünde bir değişkene if let yapısı ile kaydetmeyi deniyoruz. Eğer bu işlem başarılı olursa, hücremizin içindeki UILabel elementlerinin metinlerini ve UIImageView elementinin görselini içeriğimizde karşılık gelen alanlara eşitliyoruz ve hücremizi döndürüyoruz. 👍
Eğer bu işlem sırasında bir hata olur da başarılı olamazsak, uygulamamızın hata vermemesi adına boş bir hücre dönüyoruz 🙃
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let article = articles[indexPath.row]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ArticleCell", for: indexPath) as? ArticleCollectionViewCell {
cell.imageView.image = article.image
cell.captionLabel.text = article.caption
cell.titleLabel.text = article.title
return cell
} else {
return UICollectionViewCell()
}
}
Hücremizin Genişliğini Ekran Boyutuna Göre Değiştirelim
Her ne kadar UICollectionView kullanmanın -şimdilik- en kolay yolu, hücrelerin boyutunu sabit tutmak olsa da, yaptığımız uygulamanın doğası gereği hücrelerimizin genişliği ekran boyutuna göre değişmek zorunda. (Yoksa iPhone SE’de hücrelerimizin çok küçük bir kısmı görünürdü! 😀) Ancak bu hiç sorun değil, çünkü hücrelerimizin akışını düzenleyen UICollectionViewFlowLayout sınıfına eklemeler yaparak bunu kolaylıkla düzeltebiliriz! 🙂
Ekleme yapmaktan bahsettik, yani bu da demek oluyor ki yine extension kullanacağız. Bu extension’ımızda ise ViewController
sınıfımızı UICollectionViewFlowLayoutDelegate
sınıfının alt sınıfı olarak tanımlıyoruz, ve bu sınıfın hücrelerin boyutunu ayarlamaktan sorumlu sizeForItemAt
metodunda hücremizin yüksekliğini sabit, genişliğini ise ekran boyutuna göre (her iki kenarda da 16 pt boşluk kalacak şekilde) hesaplıyoruz. Son satırda da bu bilgileri, içinde bu değerleri bulunduran CGSize türünde bir değişken ile dönüyoruz.
extension ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.frame.width - 16.0 * 2
let height: CGFloat = 234.0
return CGSize(width: width, height: height)
}
}
Uygulamamız Hazır! 🥳
Bu satırdan sonra ise, artık uygulamamız en yeni haberleri göz alıcı bir biçimde göstermeye hazır!
Örnek uygulamayı incelemek ve kendiniz denemek isterseniz kaynak kodları GitHub üzerinden bulabilirsiniz:
Böylelikle UICollectionView elementinin temel özelliklerini ve çalışma mantığını öğrenmiş bulunduk, hatta gerçek bir uygulamada kullanılabilecek türden bir örnek projeyle de öğrendiklerimizi uygulamış olduk! Edindiğimiz bu bilgiler sayesinde artık siz de uygulamalarınızda birbirinden farklı ve kullanışlı görünümler yaratabilirsiniz. 💫 Hepinize iyi kodlamalar! 🖥
Swift Öğrenin. Uygulama Geliştirin. Sınırların Ötesine Geçin.
Hem kod yazmaya yeni başlayanların hem de profesyonellerin rahatlıkla takip edebilecekleri 40 saatlik videolu eğitim ile Swift programlama dilini derinlemesine keşfedin. Eğitim boyunca karşılaşacağınız problemleri birebir online görüşmelerde çözün.