UICollectionView基礎進階(一)+ 更輕量的Controller

前言

本文介紹了UICollectionView的用法的擴展,不涉及基礎的用法,是我對UICollectionView用法的總結和實戰,通過這篇文章,讀者可以瞭解到使用自定義的UICollectionViewDataSouce來使UIViewController更加輕量,使用Model來使UIViewController更加輕量,在下篇文章中,我會繼續介紹UICollectionViewLayout的擴展,並且使用UICollectionViewLayout做出一些酷炫的動畫,如文章中有錯誤,歡迎大家指出。

文章參考於:Objc.IO,王巍的博客


UICollectionView簡介

  • UICollectionView可以說是和UITableView的擴展,取掉UICollectionViewLayout可以說和UITableView沒有太多區別,但當使用Layout時,CollectionView就展示出了自己的高靈活性,可以實現一下非常複雜的佈局。

基本的UICollectionView設定

讓我們先做點熱身,設置一些基本的設定

  • 初始化一個UICollectionView,一定要在初始化時就將layout屬性定義在初始化中,不然程序會崩潰,然後讓其ConformdelegatedataSource,並註冊一個Cell。
  • 這一篇不介紹UICollectionViewLayout的自定義,所以先使用系統提供的UICollectionViewFlowLayout來進行初始化,UICollectionViewFlowLayout是系統提供的流式佈局,Cell按順序排開,一行裏的Cell有位置則會在同一行,沒有位置的Cell會排在下一行,UICollectionViewFlowLayout的設定可以通過屬性,也可以符合UICollectionViewDelegateFlowLayout來設定,詳情可見文檔。
    private var layout = UICollectionViewFlowLayout()
    
    private lazy var collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)

    override func viewDidLoad() {
        super.viewDidLoad()
                
        collectionView.register(LNCollectionViewCell.self, forCellWithReuseIdentifier: "LNCollectionViewCell")
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        self.view.addSubview(collectionView)
    }

UICollectionViewDataSource

  • UICollectionViewDataSouce的基本設定如下,返回一個Cell的數量,並設定Cell的樣式和使Cell能夠複用,到現在爲止基本設定已經完成。
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.items.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LNCollectionViewCell", for: indexPath) as! LNCollectionViewCell
        let item = self.items[indexPath.item]
        cell.titleLabel.text = item.text
        
        return cell
    }

更輕量的ViewController

UICollectionViewDataSource往往在Controller裏擁有着大量篇幅,多到幾十行,甚至上百行,那如何在這方面使Controller更加輕量呢,也許你會說使用extension,使用extension是一個不錯的辦法,可以使Controller更加清晰,但並沒有做到輕量,因爲代碼還是在這裏,Controller依然不堪重負

  • 自定義DataSource並將業務邏輯轉移至DataSorce的類裏,定義一個Block,使用Block爲來設置Cell
	var ConfigureCellBlock: ((_ cell: LNCollectionViewCell, _ indexPath: IndexPath, _ item: LNToDoItem) -> Void)?

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LNCollectionViewCell", for: indexPath) as! LNCollectionViewCell
        let item = self.items[indexPath.item]
        if let setUpCellBlock = ConfigureCellBlock {
            setUpCellBlock(cell, indexPath, item)
        }
        
        return cell
    }

現在可以把ViewController中的代碼取掉了

  • 簡單的使用幾行,就可以了
    private var dataSource = LNCollectionViewDataSource()

	collectionView.dataSource = dataSource
        
    dataSource.ConfigureCellBlock = { cell, indexPath, item in
    	let text = item.title
        cell.titleLabel.text = text
    }

隨着業務邏輯增加,DataSource的類減輕的負擔就越明顯

讓Model做自己該做的事

  • 爲Model定義儲存類,使Model做自己的事,而使代碼從ViewController中分離出來,ViewController只負責處理協調Model和View,MVC之間應該使用單向流程,當Model發生變化,應該間接向Controller彙報。
class LNStore {
    static var shared = LNStore()
    
    private(set) var items = [LNToDoItem]()
    
    var count: Int { items.count }
    
    var indices: Range<Int> { items.indices }
    
    init() {  }
    
    func append(item: LNToDoItem) {
        items.append(item)
    }
    
    func remove(item: LNToDoItem) {
        guard let index = items.firstIndex(of: item) else { return }
        items.remove(at: index)
    }
    
    func remove(at index: Int) {
        items.remove(at: index)
    }
    
    func edit(origin: LNToDoItem, new: LNToDoItem) {
        guard let index = items.firstIndex(of: origin) else { return }
        items[index] = new
    }
}

將View轉移到View層

  • View的定義轉移到自己的類裏,而不是在viewDidLoad()中設置,該方法只用來設定一些View在自己的類中無法單獨實現的設置

總結

這一篇寫了UICollectionView的基礎實現以及UIViewController的輕量級的優化,下一篇會更加深入的講解關於UICollectionViewLayout的自定義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章