基于MVC拆分TableView的Cell動(dòng)態(tài)創(chuàng)建模型

本文主要介紹在MVC模式下,拆分TableView的代理,實(shí)現(xiàn)不同數(shù)據(jù)源動(dòng)態(tài)創(chuàng)建不同的Cell。

文件結(jié)構(gòu)如下:

文件結(jié)構(gòu)圖示.png

文件結(jié)構(gòu)解析

Controllers

這里放的是頁(yè)面的Controller,主要負(fù)責(zé)邏輯加載和設(shè)置TableView的代理

Models
  • Items
    一個(gè)item對(duì)應(yīng)一個(gè)Cell,對(duì)數(shù)據(jù)的單元封裝
  • DataSource
    自定義的DataSource子類,用于實(shí)現(xiàn)TableView的UITableViewDataSource代理,并且分發(fā)item與Cell的對(duì)應(yīng)關(guān)系

model主要接收數(shù)據(jù),封裝成item,并加入數(shù)組

Views
  • Cells
    自定義與item一一對(duì)應(yīng)的Cell

重點(diǎn)解析

TableView有兩個(gè)代理,分別是是UITableViewDelegate和UITableViewDataSource,這里需要重點(diǎn)針對(duì)UITableViewDataSource進(jìn)行一些定制。

LittleHTableViewDataSource

首先我們自己定義一個(gè)協(xié)議LittleHTableViewDataSourcePotocol具體如下:

public protocol LittleHTableViewDataSourcePotocol:NSObjectProtocol,UITableViewDataSource
{
    func tableView(_ tableView:UITableView, objectForRowAt indexPath:IndexPath) -> AnyObject?
    
    func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type
    
    func tableView(_ tableView: UITableView, indexPathForObject object: AnyObject) -> IndexPath?
    
    func tableView(_ tableView: UITableView, cell:UITableViewCell, willAppearAtIndexPath indexPath: IndexPath) -> Void
}

然后我們聲明一個(gè)自定義的DataSource類,實(shí)現(xiàn)LittleHTableViewDataSourcePotocol協(xié)議

public class LittleHTableViewDataSource: NSObject,LittleHTableViewDataSourcePotocol {
    public var items : NSArray
    
    public init(items : NSArray) {
        self.items = items
    }
    
    // MARK:
    // MARK: -LittleHTableViewDataSourcePotocol 方法
    public func tableView(_ tableView: UITableView, objectForRowAt indexPath: IndexPath) -> AnyObject? {
        if indexPath.row < self.items.count {
            return self.items.object(at: indexPath.row) as AnyObject?
        } else {
            return nil
        }
    }
    
    public func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type {
        return LittleHTableViewBaseCell.self
    }
    
    public func tableView(_ tableView: UITableView, indexPathForObject object: AnyObject) -> IndexPath? {
        return nil
    }
    
    public func tableView(_ tableView: UITableView, cell:UITableViewCell, willAppearAtIndexPath indexPath: IndexPath) -> Void {
        
    }
    
    // MARK:
    // MARK: -UITableViewDataSource方法
    
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let object:AnyObject? = self.tableView(tableView, objectForRowAt: indexPath)
        
        var cell1:UITableViewCell
        
        if let obj1 = object {
            let cellClass:LittleHTableViewBaseCell.Type = self.tableView(tableView, cellClassForObject: obj1)
            let identifier:String = cellClass.LittleHIdentifier()
            var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: identifier)
            if cell == nil {
                cell = cellClass.init(style: UITableViewCellStyle.default, reuseIdentifier: identifier)
            }
            cell1 = cell!
        } else {
            cell1 = LittleHTableViewBaseCell(style: UITableViewCellStyle.default, reuseIdentifier: nil)
        }
        
        if cell1 is LittleHTableViewBaseCell {
            let cell2 = cell1 as! LittleHTableViewBaseCell
            cell2.setObject(object)
        }
        
        return cell1
    }
    
    public func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    

    open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        if let view1 = tableView.tableHeaderView {
            if index == 0 {
                tableView.scrollRectToVisible(view1.bounds, animated: false)
                return -1
            }
        }
        
        //        let index2 = advance(title.startIndex, 1)
        var index2:String.Index = title.startIndex
        index2 = title.index(index2, offsetBy: 1)
        
        let letter:String = title.substring(to: index2)
        let sectionCount:Int = tableView.numberOfSections
        
        var i:Int = 0
        for _ in 1...sectionCount {
            let section :String = (tableView.dataSource?.tableView!(tableView, titleForHeaderInSection: i))!
            if section.hasPrefix(letter) {
                return i
            }
            i += 1
        }
        
        if index > sectionCount {
            return sectionCount - 1
        } else {
            return index
        }
    }
}

在我們自己定義的這個(gè)DataSource里面可以看到已經(jīng)實(shí)現(xiàn)了UITableViewDataSource,我們通過(guò)LittleHTableViewDataSourcePotocol協(xié)議的

func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type

方法獲取到具體Cell的classType,然后創(chuàng)建這個(gè)類型的Cell,并且通過(guò)LittleHTableViewDataSourcePotocol協(xié)議的

func tableView(_ tableView:UITableView, objectForRowAt indexPath:IndexPath) -> AnyObject?

方法獲取Cell對(duì)應(yīng)的數(shù)據(jù),在Cell的setObject方法中進(jìn)行數(shù)據(jù)賦值。

Controller關(guān)鍵代碼

在我們使用到tableView的地方,將tableView的UITableViewDataSource代理設(shè)置為這個(gè)類的對(duì)象。如:

public var dataSource : LittleHTableViewDataSource?{
        get{
            return _dataSource
        }
        
        set{
            if newValue != _dataSource {
                _dataSource = newValue
            }
            
            if let tableView1 = self.tableView {
                tableView1.dataSource = _dataSource
                tableView1.reloadData()
            }
        }
    }

我們希望Cell的高度能在Cell內(nèi)部返回,最好在item數(shù)據(jù)封裝的時(shí)候就直接計(jì)算好Cell的高度,然后直接返回,實(shí)現(xiàn)UITableViewDelegate的下面方法將返回的高度的任務(wù)轉(zhuǎn)移到Cell

open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if (tableView.dataSource is LittleHTableViewDataSource) {
            let dataSource:LittleHTableViewDataSource? = tableView.dataSource as? LittleHTableViewDataSource
            if let d1 = dataSource {
                let object = d1.tableView(tableView, objectForRowAt: indexPath)
                if let obj1 = object {
                    let t1:LittleHTableViewBaseCell.Type =  d1.tableView(tableView, cellClassForObject: obj1)
                    return t1.tableView(tableView, rowHeightForObject: obj1)
                }
            }
        }
        return 44.0
    }

Cell

cell上需要實(shí)現(xiàn)

public func setObject (_ obj:AnyObject?) -> Void

來(lái)獲取數(shù)據(jù)
實(shí)現(xiàn)

public class func tableView(_ tableView: UITableView, rowHeightForObject object: AnyObject) -> CGFloat

獲取高度

實(shí)現(xiàn)

public class func LittleHIdentifier() -> String

設(shè)置reuseIdentifier

主要思路,將TableView的UITableViewDataSource的Cell構(gòu)建能夠根據(jù)classType去動(dòng)態(tài)構(gòu)建,把數(shù)據(jù)類型item和Cell一一對(duì)應(yīng)。

demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容