iOS UIKit Compositional Layout
iOS UIKit: Compositional Layout Kullanımı

iOS UIKit ile Compositional Layout‘un nasıl kullanıldığını bu içerikte detaylı bir şekilde anlatmaya çalışacağım. Compositional Layout, iOS 13 ile birlikte gelen CollectionView’ın daha esnek ve daha modüler bir yapıda olmasına olanak sağlayan bir yapıdır.

Bu yapı ile birlikte oldukça karmaşık bir sayfayı bile hücrelere bölerek tasarlayabilir, dinamik uzunlukta listeler elde edebiliriz. Benzer sonuçları ScrollView kullanarak da alabiliriz ancak bir takım sabit uzunluklar vermek ve bazı tasarımların farklılığından dolayı ScrollView ile istediğimiz sonuçları almamız pek mümkün olmuyor.

İşte bu noktada sayfamızı tasarlarken Compositional Layout’dan faydalanıp tek bir CollectionView kullanarak farklı tasarımları entegre edebiliriz. Peki bu yapının bizim açımızdan avantaj ve dezavantajları nedir bir bakalım.

Avantajları

  • Esneklik: Compositional Layout’un en önemli faydalarından birisi kesinlikle esnekliktir. En karmaşık ekranları bile tasarlarken büyük bir kolaylık sağlar.
  • Detaylandırılabilir: Her hücre, grup ve bölüm birbirinden farklı şekilde dizayn edilebilmektedir.
  • Performans: Bu konuda da Compositional Layout bize büyük bir fayda sağlıyor çünkü tek bir CollectionView nesnesi üzerinden sayfada yer alacak olan tüm kaydırılabilir nesneleri hareket ettirebiliyoruz. Unutmayın bir sayfa içerisinde ne kadar az kaydırılabilir eleman varsa o kadar yüksek performans alırız. Bir ScrollView içerisinde CollectionView koymanın performans açısından bir çok dezavantajı vardır.

Dezavantajları

  • Zorluk Seviyesi: İlk etapta öğrenmesi ve özümsemesi zaman alan bir yapı ancak bir kaç basit örnek ve birazcık çaba ile hiçte zor olmadığını sizde birazdan göreceksiniz.
  • Zaman: Basit, bir kaç ekranlı uygulamalar için karmaşıklık düzeyi biraz yüksek olduğundan gereksiz vakit uzatabilir.

Avantaj ve dezavantajlarına değindikten sonra kendimce ve uzun bir süre yaptığım araştırmalar sonucunda şunu net bir şekilde söyleyebilirim ki: Tek bir ScrollView içerisine elemanları dolduru, sayfayı kaydırmak yerine tek bir CollectionView ile tüm sayfayı kontrol etmek çok daha iyi bir seçim.

Şimdi Compositional Layout ile neler yapabileceklerimize bir bakalım.

Trendyol, Hepsiburada, Amazon, YouTube gibi birden fazla component içeren karmaşık ekranları oluşturabiliriz.

Normalde bu karmaşıklıkta bir ekranı ScrollView kullanarak yapmak oldukça zor. Bir de ScrollView içerisinde dinamik uzunlukta dikey listelenen bir CollectionView kullanmak istediğinizde durum iyice çığırından çıkar ve saç baş yolmaya başlarsınız. Daha fazla uzatmadan bir örnek yapalım. Bu örneğimizde en üstte bir header, altında soldan sağa kayan bir kategori listesi, onun da altında ürünler listesi yacağız.

  • Bir tane UICollectionView oluşturalım
    let myCollectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.register(UINib(nibName: "TopMenuCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "TopMenuCollectionViewCell")
        collectionView.register(UINib(nibName: "CategoryCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CategoryCollectionViewCell")
        return collectionView
    }()

CollectionView’ımızı oluşturup, içerisine iki tane cell ekledik. Bu cell’leri XIB ile oluşturduk. Bir sonraki örnekte cell’leri programatik olarak nasıl yapacağımızı da inceleyeceğiz.

  • ViewDidLoad’a bir kaç ekleme yapalım
  override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(myCollectionView)
        myCollectionView.delegate = self
        myCollectionView.dataSource = self
        setupConstraint()
        setupCompositionalLayout()
    }

Burada oluşturduğumuz CollectionView’ı ana view’ımıza ekledik ve gerekli ayarlamalarını yaptık. Bu kısımları hızlı geçiyorum çünkü önceki makalelerde CollectionView Kullanımı hakkında detaylı bir paylaşım yapmıştım.

  • setupConstraint fonksiyonumuz;
    func setupConstraint(){
        NSLayoutConstraint.activate([
            myCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            myCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            myCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            myCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

CollectionView’ın ekrana tam bir şekilde oturmasını sağlayarak geniş bir görünüm elde ettik.

Şimdi bundan sonraki kısımda asıl büyük işlemin setupCompositionalLayout() fonksiyonu ile yapıldığını göreceğiz. Bir çok detay burada yer alıyor bu noktaya kadar geldiyseniz şimdi çok daha dikkatli bir şekilde takip etmenizde fayda var.

  • setupCompositionalLayout fonksiyonu
 func setupCompositionalLayout(){
        let layout = UICollectionViewCompositionalLayout{ sectionIndex, environmentData in
            if(sectionIndex == 0){
                let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
                let item = NSCollectionLayoutItem(layoutSize: itemSize)
                
                let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
                let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
                
                let section = NSCollectionLayoutSection(group: group)
                return section
                
            }else if sectionIndex == 1 {
                let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(150), heightDimension: .estimated(40))
                let item = NSCollectionLayoutItem(layoutSize: itemSize)
                
                let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(150), heightDimension: .estimated(40))
                let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
                
                let section = NSCollectionLayoutSection(group: group)
                section.orthogonalScrollingBehavior = .continuous
               section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
                return section
            }
            
            else{
                let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(200))
                let item = NSCollectionLayoutItem(layoutSize: itemSize)
                
                let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(200))
                let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
                
                let section = NSCollectionLayoutSection(group: group)
    
                return section
            }
            
        }
        myCollectionView.setCollectionViewLayout(layout, animated: true)
    }

Bu kadar kodu birden görünce gözünüz korkmasın 😀 Şimdi tek tek hangi satır ne işe yarıyor hepsini anlatacağım.

Öncelikle Compositional Layout’un nasıl çalıştığından kısaca bahsedeyim ki kodları anlamamız bir o kadar kolay olsun.

Compositional Layout’da temel olarak dikkat etmemiz gereken 3 yapı var. Item, Group ve Section. Şimdi aşağıdaki görsel ile bu üç yapının ne olduğunu net bir şekilde anlayalım.

En dıştaki kapsayıcı yapımız Section, onun içinde yer alan ve tüm item’ları tutan yapımız Group ve her bir kırmızı yapı da Item‘larımızı temsil ediyor.

Satır Satır Gidelim

let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return section

NSCollectionLayoutSize: Her bir kırmızı öğenin boyutunu veriyoruz. Ekranda yer alacak olan her item’ın boyutunu NSCollectionLayoutSize kullanarak belirtiyoruz. Peki bu içlerinde kullandığımız fractionalWidth ve absolute gibi değerler nedir? Hepsini açıklayayım.

Compositional Layout’da bir boyut verirken üç farklı şekilde verebiliyoruz. Bunlar;

absolute: Öğenin gerçek net değerini biliyorsak kullanırız. Mesela bir ikon ekledim ve boyutu kesinlikle 50×50 olacağını biliyorum. O zaman widthDimension ve heightDimension parametrelerine .absolute(50) değeri veriyoruz.

estimated: Bir öğenin boyutunu tam olarak bilmiyorsak yaklaşık bir değer verip, layout oluşturulduğunda otomatik olarak boyutlandırılmasını sağlıyor.

fractionalWidth / fractionalHeight: Yüzdelik olarak boyut vermemizi sağlıyor. Width kısmında 0.4 verirsek ekran genişliğin yüzde 40’ını, yükseklik kısmında 0.6 yazarsak ekran yüksekliğinin yüzde 60’ını boyut olarak alır.

NSCollectionLayoutItem: Her bir item için bir layout oluşturup, o layout’un size’ını az önce oluşturduğumuz parametre ile veriyoruz. Yukarıdaki kod satırında şunu demiş olduk: genişliğimi ekran genişliğinin yüzde yüzü olarak al, yüksekliği de net olarak 50 olarak ver.

NSCollectionLayoutGroup.horizontal: Burada ise item’leri tutacak olan grubumuzu tanımlıyoruz. Bir üst satırda genişlik ve yükseklik satırını verdikten sonra elemanların bir grup içerisinde kaç eleman olacağını da belirttik. subItems parametresiyle bir grup içinde kaç eleman olacağını belirtebiliyoruz. Eğer subItems[item,item] yaparsak bir satırda iki eleman görünecektir.

Eğer dikey bir listeleme yapmak istiyorsak NSCollectionLayoutGroup.vertical kullanabiliriz.

NSCollectionLayoutSection: Section ise bizim her bir bölümümüzü ifade ediyor. CollectionView ile daha önce bir kaç örnek yaptıysanız daha önce görmüşsünüzdür. Varsayılan olarak section sayısı 1 gelir ve tüm liste aynı dizayn elemanları gösterir. Ancak section sayısını arttırdığımızda listeye bölümler eklemiş oluruz. Bu eklediğimiz bölümleri de kod içerisinden yakalayarak hangi tasarımda cell göstereceğimize karar veriririz.

Kodun genel bir açıklamasını yaparksak;

UICollectionViewCompositionalLayout tipinde bir layout değişkeni tanımladım ve closure olarak başlatıp bana gelecek olan iki tane parametreye isim verdim. sectionIndex ve environmentData ile UICollectionView tarafından gönderilecek olan parametreleri aldım.

SectionIndex ile hangi bölümde olduğumuz tespit edip, o bölümlere uygun boyut ayarlamalarını gerçekleştirip, en son setCollectionViewLayout fonksiyonunu kullanıp, CollectionView’ıma Compositional Layout’u aktarmış oldum.

CollectionView için yazmamamız gereken zorunlu fonksiyonlar

extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if(section == 0){
            return 1
        }else if section == 1{
            return categoryList.count
        }
        else{
            return 5
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if(indexPath.section == 0 ){
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TopMenuCollectionViewCell", for: indexPath) as! TopMenuCollectionViewCell
            return cell
        }else if indexPath.section == 1 {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCollectionViewCell", for: indexPath) as! CategoryCollectionViewCell
            cell.categoryLabel.text = categoryList[indexPath.row].categoryName
            cell.categoryImage.image = UIImage(named: categoryList[indexPath.row].categoryImage ?? "")
            return cell
        }
        else{
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TopMenuCollectionViewCell", for: indexPath) as! TopMenuCollectionViewCell
            return cell
        }
    }
}

Burada dikkat ettiyseniz section sayısını 2 verdim çünkü 2 tane bölüm olsun istedim.

cellForItemAt fonksiyonunda ise indexPath.section üzerinden hangi section’da olduğumu anlayıp, o sectionlara özel cell tasarımlarımı göstermiş oldum.

Cell tasarımlarına çok fazla değinmedim ancak hepsini XIB ile yapıp, CollectionView’a ekledim. Uygulamanın son çıktısı görseldeki gibi oldu.

Çok daha detaylı ve karmaşık ekran tasarımlarının nasıl yapılacağınıda paylaşacağım. Şimdilik yazıyı burada sonlandırıyorum. Kafanızı karıştıran, anlamadığınız noktalar olursa lütfen yorumlarda belirtin.

Flutter Bloc Kullanımı (En Optimize Yol)
Flutter Bloc ile State Management Örneği

Flutter Bloc ile State management başlıklı bu makalede olabilecek en iyi şekilde bir state’i nasıl yönetiriz, bu state yönetimi sırasında kullanıcının ekranındaki verileri kaybetmedene nasıl state yenilemesi yapabiliriz detaylarıyla bundan bahsedeceğim.

Flutter Error Handling Nasıl Uygulanır
Flutter Error Handling Nasıl Uygulanır (Either ile)

Flutter Error Handling, mobil uygulamalar için olmazsa olmaz konular arasında yer alıyor. Uygulamanın kullanıcı ile yüksek etkileşimde olmasının en önemli kriterlerinden birisi olan Error Handling’in Flutter tarafında nasıl uygulanabileceğini bu makalede göstermeye çalışacağım.

Flutter Network Manager Dio İle
Flutter Network Manager (Dio ile)

Flutter network manager konusu oldukça önemli ve bir o kadarda detay barındıran bir başlıktır. Bu makalede Dio paketini kullanarak nasıl bir Network Manager oluşturabiliriz, oluşturduğumuz manager’ı daha ne kadar geliştirebileceğimizden bahsedeceğim.

Flutter Firebase Cloud Messaging Nasıl Entegre Edilir
Flutter Firebase Cloud Messaging ile Sayfa Yönlendirme

Flutter ile Firebase Cloud Messaging kullanarak uygulama içerisinde push notifications’ları yönetebiliriz. Gelen bir bildirime tıkladıktan sonra detay sayfasına yönlendirme işlemi o kadar da basit görünmüyor. Gelin birlikte bunu nasıl uygulayabileceğimize bir bakalım.

iOS UIKit: UICollectionView Kullanımı (XIB İle)

iOS UIKit kullanarak XIB ile nasıl özel CollectionViewCell tasarlayabiliriz bu yazımızda detaylıca öğreneceğiz. Öncelikle XIB nedir ondan bahsedelim. XIB, XML Interface Builder’ın kısaltılmışıdır ve arayüz kodlamalarını çok daha hızlı ve görsel olarak yapmamıza olanak sağlayan oldukça faydalı bir araçtır.

Bu araç yardımı ile programatik kodlamadan çok daha hızlı bir şekilde tasarımlar yapabilir ve çıktılar alabiliriz. XIB kullanmanın bir çok noktada avantajı olsa da dezavantajlı olduğu bir kaç madde de var elbette.

Avantajları

  • XIB ile arayüzleri çok hızlı bir şekilde oluşturabiliriz. Programatik’e göre neredeyse üç dört kat daha hızlı bir şekilde tasarımları oluşturup, kodumuza entegre edebiliriz.
  • Programatik tarafta oluşan kod karmaşıklığını azaltır.
  • Okunabilir ve yönetilebilir bir yapı sunar. Proje büyüdükçe kodlar içerisinde boğulmak yerine ilgili tasarım dosyasına gidip, değişiklikleri sadece orada yapabilirsiniz.

Dezavantajları

  • Kolaya alışmak sanıldığı kadar da iyi bir şey değil. Sürükle bırak ile yapmak bir süre sonra programatik düşünceden sizi uzaklaştırabilir.
  • Sektörde büyük ölçekli projelerde programatik’in daha yaygın olduğu projelerde görev aldığınızda geçiş süreciniz zorlaşabilir. Bundan dolayı programatik kısmı kesinlikle ihmal etmemek gerek.

Kısaca XIB’den bahsettikten sonra dilerseniz örneğimize geçelim. Örneğimizde basit bir CollectionView ve Cell tasarımı uygulayacağız. Burada önemli olan tasarımın basitliği değil, işlevselliği olacaktır. Çok daha karmaşık tasarımları dahi XIB yardımıyla yapmamız mümkündür. İlerleyen örneklerde bunları sıklıkla yapacağız.

Not: Projede sadece cell tasarımını XIB ile yapacağız, UICollectionView’ı programatik olarak kodlayacağız.

Bir örnek proje başlatın ve UICollectionView’ı kodlamaya başlayalım

Öncelikle programatic kısımda eksiklikleriniz var ise sitemizden daha detaylı anlatımlar yaptığım programatik örneklere bakmanızı tavsiye ederim. Çünkü burada programatik kodlamayı anlatmayacağım.

Programatik olarak UICollectionView’ı kodlayalım

    let myCollectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout )
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()

Yukarıdaki kodun kısaca açıklaması şu şekilde; Bir tane layout oluştur. Bu layout UIKit tarafından hazır olarak sunulan UICollectionViewFlowLayout sınıfıdır. Bu sınıfı kullanarak üzerinde bir çok özelleştirme yapabildiğim, işimizi kolaylaştıran bir yapıdır. CollectionView üzerindeki elemanların hizalanması, hücre boyutlarının değiştirilmesi, kenar boşlukları gibi bir çok özelleştirme imkanı sunmaktadır.

İkinci satırda ise bir tane UICollectionView tanımladık. Frame olarak .zero verdik. Bu şu anlama geliyor;

Koordinat düzlemininde (0,0) noktasını baz al ve oraya yerleşim yap. Sana boyut verene kadar da o şekilde kal

Böyle dediğimizde UICollectionView nesnesinin ekranda görünmemesini sağladık. CollectionView’ın ekrandaki yerleşimini biraz sonra constraint atamasıyla gerçekleştireceğiz.

Viewdidload’da bir kaç düzenleme yapalım.

    override func viewDidLoad() {
        super.viewDidLoad()
       
        view.addSubview(myCollectionView)
        myCollectionView.backgroundColor = .red
        makeConstraint()
        myCollectionView.dataSource = self
        myCollectionView.delegate = self
    }

Burada ViewController’ın view’ına az önce oluşturduğumuz UICollectionView’ı ekledik ve bir renk ataması yaptık. DataSource ve delegate parametrelerini de eşitledikten sonra makeConstraint() isimli bir fonksiyon ile UICollectionView nesnesinin ekrandaki yerleşimini yönettik.

    func makeConstraint(){
        NSLayoutConstraint.activate([
            myCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            myCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            myCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            myCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
    }

Bunları yaptıktan sonra uygulamayı çalıştırdığımızda bir şey görmemiz mümkün değil. Çünkü zorunlu fonksiyonları tanımaladık ve cell tasarımını oluşturmadık.

New File -> Cocoa Touch Class -> UICollectionViewCell

Adımlarını izleyerek kendi CollectionViewCell sınıfımızı oluşturabiliriz. Also create XIB file seçeneğini seçmeyi unutmayın!

Ben dosyaya MyCollectionViewCell ismini verip, Subclass’ı UICollectionViewCell olarak seçtim. Siz Class ismini değiştirebilirsiniz ama örneği birebir yapabilmek için aynı bırakmanızda fayda var.

Next dediğinizde iki tane dosya oluşturması gerekiyor. Bu dosyalardan birisi cell için kodlama yapacağımız sınıf, diğeri ise tasarım yapacağımız XIB dosyasıdır. XIB dosyasını açıp, bir boyut veriyoruz.

Sol taraftan MyCollectionView’ı seçip, sağ taraftaki üçgene tıklayıp cell’e bir boyut veriyoruz. Şimdi bu vereceğimiz boyutlar kafanızı karıştırmasın. Sonraki yazılarda nasıl dinamik boyutlu cell’ler tasarlayabileceğiniz konusuna da değineceğim.

Ben 375×100 boyutunda bir cell yaptım. Siz de şimdilik bu boyutu girip, ekrandaki değişiklikleri görebilirsiniz.

Şimdi bu cell içerisine bir tane UIView ekleyelim. Sağ üstteki + butonuna basarak ekleme yapabilirsiniz. UIView’ı ekledikten sonra constraintlerini verip, UIView’ın arka plan rengini turuncu yaptım.

Aynı şekilde UIView içerisine bir tane de UILabel ekleyip, MyCollectionViewCell.swift dosyama label’ı control tuşuna basılı tutarak sürükleyip bıraktım.

Cell ile ilgili işlemlerimizi tamamladık. Şimdi ViewController’a geri dönüp yarım kalan işimizi tamamlayalım.

İlk başta yaptığımız UICollectionView sabitimize gidip bir satır eklemesi yapacağız. Bu satır, XIB ile oluşturduğumuz cell’i, UICollectionView’a ekleyip, kullanmamızı sağlayacak.

    let myCollectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout )
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.register(UINib(nibName: "MyCollectionViewCell", bundle: nil), 
          forCellWithReuseIdentifier: "MyCollectionViewCell")
        return collectionView
    }()

Eklediğimiz satır; collectionView.register fonksiyonu.

Bu fonksiyon sayesinde XIB ile oluşturduğumuz hücre tasarımını UICollectionView’a eklemiş olduk. Peki eklemek ne demek? UICollectionView’a dedik ki: Bu tasarımı bünyene dahil et, yeri geldiğinde kullanacağım.

forCellWithReuseIdentifier, cell’ime verdiğim benzersiz bir id’dir Cell kullanırken bu id üzerinden erişim sağlayacağım.

Son olarak bir de extension yazıp, UICollectionView için zorunlu fonksiyonlarımızı entegre edelim.

extension ViewController : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionViewCell", for: indexPath) as! MyCollectionViewCell
        cell.myLabel.text = String(indexPath.row)
        return cell
    }
}

Kodumuzuda ekledikten sonra bir de CollectionView sabitimize gidip, cell için oluşturduğumuz genişlik değerlerini atadığımızda işlem tamamlanmış oluyor. Kodlama sonunda aşağıdaki görüntüyü elde etmiş olmamız gerekiyor. Simülator iPhone 14 Pro olduğu için genişliği 375 olarak sabit verdim örnek olması amacıyla. Siz kullandığınız simülatörün ekran genişliğini verebilirsiniz.

Böylelikle UICollectionView’a XIB ile nasıl custom cell eklenir öğrenmiş olduk. Bir sonraki içerikte görüşmek üzere.