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.

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.

iOS UIKit: UICollectionView Kullanımı

iOS UIKit UICollectionView, mobil uygulamalarımız için liste düzeninde veya ızgara düzeninde verileri yansıtmamızı sağlayan bir arayüz öğesidir. UICollectionView sayesinde dilediğimiz çeşitlikte tasarıma sahip sayfalar yapabilir, dinamik ekran boyutlarına göre uygun listelemeler yapabiliriz.

Instagram, YouTube, Netflix, Amazon ve daha binlerce mobil uygulamada UICollectionView kullanılıyor ve kullanılmayada devam edecek. Hepsi farklı tasarımlarda olsada işlevsellik açısından hepsinin ortak noktası var: Bir veri kaynağından verileri almak ve bir düzen çerçevesinde ekrana basmak.

Tabii işin içerisine ince tasarım çalışmaları girince çok karışıkmış gibi görünebiliyor ancak temel olarak UICollectionView’ın çalışma prensibini öğrendikten sonra tasarım konusu işin en zevkli kısmı oluyor. Detaylı tasarım konusunda da makaleler yazacağım ancak bu makalenin konusu temel olarak bir UICollectionView tanımlamak ve elimdeki verileri ekranda göstermek olacak. İlerleyen yazılarda Trendyol, Hepsiburada, Netflix, Instagram gibi uygulamaların anasayfalarının nasıl yapıldığını, birden fazla yöntem ile tek tek göstereceğim.

CollectionView kullanırken bilmemiz gereken bir kaç detay yer alıyor. Bunların neden kullanıldığını şimdiden öğrenirsek örnekleri çok daha iyi bir şekilde anlarız.

Cell

Cell, UICollectionView ve UITableView’da kullanılan, hücre anlamına gelen bir öğedir. Bu öğe sayesinde her bir satır veya sütun için verilerimizi gösterebileceğimiz alan elde ederiz. Yan yana iki tane kutucuk yapmak istiyorsam bu her bir kutucuk, alt alta liste yapmak istiyorsam her bir satır bir cell olarak ifade edilir.

Delegate

Delegate, ilk etapta anlaması zor gibi görünse de aslında çok basit olan, sadece diğer örneklerde biraz karışık anlatıldığı için kafa karıştıran bir yapı olarak görünüyor. Delegate kavramı iOS uygulama geliştirme aşamasında sıklıkla karşılaşacağımız bir yapı olacağı için temelden iyi anlamak ileriki zamanlar için oldukça faydalı olacaktır. Ama derinlemesine bir anlatım, bu makalenin konusu olmayacağı için sitede aratarak daha detaylı bir anlatım bulabilirsiniz.

Delegate, kullandığımız UICollectionView nesnesinin hangi sınıfa ait olduğunu anlayan bir parametredir. Örnek vermek gerekirse:

Kalem = UICollectionView

Ahmet = UIViewController

olduğunu varsayarsarsak;

collectionView.delegate = self ifadesi, Kalem Ahmet’e ait ifadesi ile aynı olmaktadır.

Yani UICollectionView gösterimi hangi ViewController için gerçekleşecek ise o sınıf ile ilişikilendirme yapıyoruz. Bir nevi birbirlerine bağlıyoruz.

Bu delegate ile bağlama işlemi bize UICollectionView için kullanmak istediğimiz fonksiyonlara erişim konusunda yardımcı oluyor. Cell için özel boyutlar, cell içerisindeki tıklamalar, cell başlıklarını değiştirme gibi konularda işimizi kolaylaştırmaktadır.

DataSource

DataSource, yukarıdaki delegate örneğinde olduğu gibi tanımlanma şekli aynı olan ve bu kısımda da veri kaynağı bağlantısı yapmamızı sağlayan parametredir. CollectionView kaç elemandan oluşacak, kaç tane section görünecek (detaylı anlatacağım), her bir cell (hücre) tasarımı nasıl olacak? Gibi sorulara cevap bulmamızı sağlayan bir yapıdır.

numberOfItemsInSection

CollectionView’ın kaç tane elemanı olacağını burada belirtiyoruz. Bir listenin eleman sayısını vermek en verimli yöntem oluyor.

cellForItemAt

Burada ise hücre tanımlamasını gerçekleştiriyoruz. Bir hücrenin nasıl bir tasarıma sahip olacağını, hücre içerisinde elemanlarda ne gibi içerikler yer alacağını buradan kontrol ediyoruz.

UICollectionViewLayout

UICollectionView için çok önemli bir yapı olmakla birlikte ızgara düzeninde, hücrelerin nasıl görüneceğine karar verir. Örnek vermek gerekirse UIKit’in bizim için tanımladığı varsayılan hücre görünümünü kullanmak istemiyorsunuz, her bir hücre boyutunu kendiniz tanımlamak istiyorsunuz. Mesela Netflix’de olduğu gibi dikdörtgen kutular tanımlamak istediğinizi varsayalım. O zaman işte UICollectionViewLayout kullanarak hücre boyutlarını özelleştirebilmekteyiz.

İlk aşama için bu kadar teknik bilgi yeterli. Şimdi bir örnek ile pekiştirme yapalım. Bu örnekte Storyboard kullanarak UICollectionView yapacağım. Birden fazla yöntem ile de nasıl yapıldığından sonraki yazılarda bahsetmiş olacağım kategori ana başlığından içerikleri bulabilirsiniz.

Storyboard ile UICollectionView kullanımı

Storyboard ile UICollectionView yapmak işin en temel noktasıdır. Direkt olarak programmatic düzende yapmak, işi anlamanızı zorlaştırabilir. UICollectionView kısmını net bir şekilde anladıktan sonra programmatic ve Xib ile de nasıl yapıldığından detaylı olarak bahsedeceğim.

Ekranın sağ üst köşesindeki + ya tıklayarak UICollectionView nesnesini ekranımıza sürükleyip bırakalım.

 

Bu şekilde bir görünüm elde ettik;

Daha sonra UICollectionView nesnemize constraint atamaları yapacağız. Constraint nedir henüz bilmiyorsanız buradan detaylarını öğrenebileceğiniz makaleye ulaşabilirsiniz. Top, left, right ve bottom’a sıfır değerlerini verip, Add Constraint dedikten sonra ekrana yayılan bir görüntü elde etmiş olacağız.

Cell Identifier Tanımalama

Kritik noktalardan birisi de burası. Hücremize bir ID tanımlaması yapmamız gerekiyor. Neden bunu yapıyoruz? Çünkü kod kısmında şunu diyeceğiz: “Eğer listeden bir eleman geldiyse şu hücre tasarımını kullan”. Bunu diyebilmek için her hücremize benzersiz bir ID vermemiz gerekiyor.

Sol taraftan Collection View Cell’i seçip, sağ taraftaki attributes kısmında yer alan Identifier kısmına “CustomCell” yazıp, enterlayalım.

Son bir adımımız kaldı. Burada da CollectionView ile ViewController arasındaki bağlantıyı sağlayacağız. Bunun için sağ üst tarafta + butonunun altında yer alan çizgiye basıp, Asistant’ı açıyoruz.

Control tuşuna basılı tutarak CollectionView nesnesini kod tarafına sürükleyip bırakıyoruz ve bir isim veriyoruz. Connection kısmının Outlet olduğundan emin olun.

Şimdi ViewController ile myCollectionView’ı birbirlerine bağlayalım. Bunun için bir extension kullanacağım. Kısaca ne işe yarıyor bu yapı onu açıklayayım daha detaylı Extension kullanım yazısına sitemizden ulaşabilirsiniz.

Bir sınıfa ek fonksiyonlar kazandırmak istediğimizde extensionlardan yararlanıyoruz. Örnek vermek gerekirse String sınıfına tersten yazdırma fonksiyonu eklemek istiyorsam bunu extension ile yapıyorum.

Daha sonra ViewController ile myCollectionView bağlama işlemlerini gerçekleştiriyorum.

Bağlantının düzgün olup olmadığını görebilmek adına myCollectionView’a bir arkaplan rengi de atadım ve sonuca baktığımızda bağlantının düzgün bir şekilde yapıldığını görebiliyoruz.

Ama bir sorun var gibi. Kod kısmında 5 tane eleman olmasını istemiştim ama hiçbirisi ekranda yok. Aslında çalışıyor ama hücrenin arkaplan rengini default verdiğimiz için şeffaf oldu. Sol taraftan Cell içerisindeki Content View’ı seçip, sağ taraftan background color’ı sarı yaptığınızda hücrelerin göründüğünü göreceksiniz.

 

Peki hücrelerin boyutunu nasıl değiştireceğiz? Yazının yukarında da bahsettiğim gibi UICollectionViewLayout ile bu düzenlemeyi yapabiliriz. UICollectionViewFlowLayout kullanarak basit bir görünüm düzenlemesi yapıp sonuca bakalım:

Gördüğünüz gibi her bir hücrenin boyutu değişti. Daha temiz kullanım için ekran genişliğini 3 e bölüp, width kısmına verebiliriz. Çok daha duyarlı bir tasarımı ilerleyen makalelerde yapacağım lütfen o yazılara da göz atmayı unutmayın.

UICollectionView hücre tasarımı yapma

UICollectionView da ye alacak olan hücrenin tasarımını Storyboard ile yapmak için ekstra bir sınıf daha oluşturmamız gerekiyor. Bu sınıf yardımıyla hücre içerisindeki elemanlara erişip, üzerlerinde değişiklik yapabiliyoruz.

Sırasıyla bu adımları uygulayın;

  • Projeye bir Cocoa Touch Class dosyası ekleyin. İsmini “MyCollectionViewCell” yapıp, tipini “UICollectionViewCell” yapın.
  • Cell içerisinde, yukarıdaki + butonuna basarak bir label ekleyip, constraintleri atayın.
  • Daha sonra Main dosyasını açıp, sol taraftan UICollectionView içerisindeki CustomCell’i seçip, sağ taraftaki class parametresine az önce oluşturduğumuz “MyCollectionViewCell” sınıfını yazıp, enterlayın.
  • Main dosyası açıkken CMD + Shift + O yapıp “MyCollectionViewCell” sınıfını Option’a basılı tutarak açın ve tanımladığınız label’ı Control tuşuna basarak sürükleyip bir isim verin.
  • ViewController sınıfına dönerek cell tanımlama kısmında istediğiniz parametreyi atayın.

Bu aşamaları yaptıktan sonra en son bu şekilde bir görüntü almanız gerekiyor.

İşte bu kadar! UICollectionView’ı Storyboard ile kullanarak tamamladık. Bundan sonraki yazılarda programmatic ve xib kullanarak collection view tanımlayacağız.

Tüm kod şu şekilde;