P9TableViewHandler 1.1.0

P9TableViewHandler 1.1.0

Tae Hyun Na 维护。



  • Tae Hyun Na

P9TableViewHandler

UITableView 是一种用于列出项的有用视图类型,但输入控制代码却是一种 boilerplate。P9TableViewHandler 库帮助您轻松简单地处理 UITableView。

安装

您可以从我们的发行页面下载最新的框架文件。P9TableViewHandler 也通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中。pod ‘P9TableViewHandler’

简单预览

let cellIdentifierForType:[String:String] = [ 
    "1" : SectionHeaderView.identifier(),
    "2" : CyanTableViewCell.identifier(),
    "3" : MagentaTableViewCell.identifier(),
    "4" : YellowTableViewCell.identifier(),
    "5" : BlackTableViewCell.identifier()
] 

let tableView = UITableView(frame .zero)

let handler = P9TableViewHandler()
handler.delegate = self
handler.standby(identifier:"sample", cellIdentifierForType: cellIdentifierForType, tableView: tableView)

var records:[P9TalveViewHandler.Record] = []
records.append(P9TableViewHandler.Record(type: "2", data: nil, extra: nil))
records.append(P9TableViewHandler.Record(type: "3", data: nil, extra: nil))

handler.sections.append(P9TableViewHandler.Section(headerType: "1", headerData: nil, footerType: nil, footerData: nil, records: records, extra: nil))

tableView.reloadData()

func tableViewHandlerCellDidSelect(handlerIdentifier: String, cellIdentifier: String, indexPath: IndexPath, data: Any?, extra: Any?) {
    // handling tableview default select action
}

func tableViewHandlerCellEvent(handlerIdentifier: String, cellIdentifier: String, eventIdentifier: String?, indexPath: IndexPath?, data: Any?, extra: Any?) {
    // handling custom event from cell
}

让我们逐一查看。

让您的 tableview cell 遵循协议

为了使用 P9TableViewHandler,您需要确认并实现以下 P9TableViewCellProtocol,并将其应用于您的 tableview cell。如果需要使用部分头部或尾部视图,也需要确认并实现相同的协议。

protocol P9TableViewCellProtocol: class {
    static func identifier() -> String
    static func instanceFromNib() -> UIView
    static func cellHeightForData(_ data: Any?, extra: Any?) -> CGFloat
    func setData(_ data: Any?, extra: Any?)
    func setDelegate(_ delegate: P9TableViewCellDelegate)
    func setIndexPath(_ indexPath: IndexPath)
}

identifier和instanceFromNib函数需要返回其标识符字符串和实例对象,以便于表格视图单元格。但是,这两个函数是可选的。除非您想进行一些自定义,否则不需要实现它们。因此,让identifier函数返回您表格视图单元格的类名,而instanceFromNib从identifier返回给定类名的实例对象。

cellHeightForData函数需要返回给定数据对应的表格视图单元格的高度。

static func cellHeightForData(_ data: Any?, extra: Any?) -> CGFloat {
    guard let data = data as? CellDataModel else {
        return 0
    }
    return data.height ?? 60
}

setData函数传递数据和额外的对象以更新您的表格视图单元格。您可以在此处编写业务代码以更新表格视图单元格。

func setData(_ data: Any?, extra: Any?) {
    guard let data = data as? CellDataModel else {
        return
    }
    self.data = data
    self.titleLabel.text = data.title ?? "Sample"
}

setDelegate函数传递回调对象以反馈自定义事件。如果您的表格视图单元格有一些自定义事件,请先在您的某个控制器上确认P9TableViewCellDelegate。

protocol P9TableViewCellDelegate: class {
    
    func tableViewCellEvent(cellIdentifier:String, eventIdentifier:String?, indexPath:IndexPath?, data:Any?, extra:Any?)
}

extension ViewController: P9TableViewHandlerDelegate {
    // ...
}

然后通过它设置代表并反馈您的自定义事件。

func setDelegate(_ delegate: P9TableViewCellDelegate) {
    self.delegate = delegate
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    delegate?.tableViewCellEvent(cellIdentifier: SampleTableViewCell.identifier(), eventIdentifier: "touch", indexPath: nil, data: data, extra: nil)
}

setIndexPath函数传递indexPath对象。您可以存储此indexPath信息并在事件代表调用中发送它。

func setIndexPath(_ indexPath: IndexPath) {
    self.indexPath = indexPath
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    delegate?.tableViewCellEvent(cellIdentifier: SampleTableViewCell.identifier(), eventIdentifier: "touch", indexPath: indexPath, data: data, extra: nil)
}

如果您的项目基于Objective C,则需要确认并实现P9TableViewCellObjcProtocol以符合您的表格视图单元格。不是P9TableViewCellProtocol,而是P9TableViewCellObjcProtocol。它具有与P9TableViewCellProtocol相同的成员函数,但您必须实现所有函数,包括identifier和instanceFromNib。

+ (NSString *)identifier {
    return @"SampleTableViewCell";
}

+ (UIView *)instanceFromNib {
    return [[[NSBundle mainBundle] loadNibNamed:[SampleTableViewCell identifier] owner:nil options:nil] firstObject];
}

处理

现在,您的表格视图单元格已就绪。为您的表格视图单元格标识符创建类型键的字典。只需根据需要创建唯一的类型键值或从服务器响应模型中获取一些类型值。

let cellIdentifierForType:[String:String] = [ 
    "1" : CyanTableViewCell.identifier(),
    "2" : MagentaTableViewCell.identifier(),
    "3" : YellowTableViewCell.identifier(),
    "4" : BlackTableViewCell.identifier()
] 

将它们设置到处理器中。并且,别忘了设置代表以从处理器接收反馈。

let handler = P9TableViewHandler()
handler.standby(identifier:"sample", cellIdentifierForType: cellIdentifierForType, tableView: tableView)
handler.delegate = self

并且,您需要为处理器创建模型数据。不用担心,您可以使用自己的模型而不做任何更改。只需将它们包装到处理器模型中。以下是处理器模型的定义。

@objc(P9TableViewRecord) public class Record : NSObject {
    var type:String
    var data:Any?
    var extra:Any?
    @objc public init(type:String, data:Any?, extra:Any?=nil) {
        self.type = type
        self.data = data
        self.extra = extra
    }
}
    
@objc(P9TableViewSection) public class Section : NSObject {
    var headerType:String?
    var headerData:Any?
    var footerType:String?
    var footerData:Any?
    var extra:Any?
    var records:[Record]?
    @objc public init(headerType:String?, headerData:Any?, footerType:String?, footerData:Any?, records:[Record]?, extra:Any?) {
        self.headerType = headerType
        self.headerData = headerData
        self.footerType = footerType
        self.footerData = footerData
        self.records = records
        self.extra = extra
    }
}

您可以通过N个部分中的M条记录制作模型,就像普通表格视图数据结构一样。创建记录和部分,并将其设置到处理器中。

var records:[P9TalveViewHandler.Record] = []
records.append(P9TableViewHandler.Record(type: "1", data: nil))
records.append(P9TableViewHandler.Record(type: "2", data: nil))

handler.sections.append(P9TableViewHandler.Section(headerType: nil, headerData: nil, footerType: nil, footerData: nil, records: records, extra: nil))

并且,重新加载目标表格视图。

tableView.reloadData()

现在,通过确认协议P9TableViewHandlerDelegate从每个表格视图单元格获取消息。以下是协议和实现示例。

@objc public protocol P9TableViewHandlerDelegate: class {
    @objc optional func tableViewHandlerWillBeginDragging(handlerIdentifier:String, contentSize:CGSize, contentOffset:CGPoint)
    @objc optional func tableViewHandlerDidScroll(handlerIdentifier:String, contentSize:CGSize, contentOffset:CGPoint)
    @objc optional func tableViewHandlerDidEndScroll(handlerIdentifier:String, contentSize:CGSize, contentOffset:CGPoint)
    @objc optional func tableViewHandler(handlerIdentifier:String, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
    @objc optional func tableViewHandler(handlerIdentifier:String, willDisplayHeaderView view: UIView, forSection section: Int)
    @objc optional func tableViewHandler(handlerIdentifier:String, willDisplayFooterView view: UIView, forSection section: Int)
    @objc optional func tableViewHandler(handlerIdentifier:String, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
    @objc optional func tableViewHandler(handlerIdentifier:String, didEndDisplayingHeaderView view: UIView, forSection section: Int)
    @objc optional func tableViewHandler(handlerIdentifier:String, didEndDisplayingFooterView view: UIView, forSection section: Int)
    @objc optional func tableViewHandlerCellDidSelect(handlerIdentifier:String, cellIdentifier:String, indexPath:IndexPath, data:Any?, extra:Any?)
    @objc optional func tableViewHandlerCellEvent(handlerIdentifier:String, cellIdentifier:String, eventIdentifier:String?, indexPath:IndexPath?, data:Any?, extra:Any?)
}
extension ViewController: P9TableViewHandlerDelegate {
    
    func tableViewHandlerCellDidSelect(handlerIdentifier: String, cellIdentifier: String, indexPath: IndexPath, data: Any?, extra: Any?) {
        
        print("handler \(handlerIdentifier) cell \(cellIdentifier) indexPath \(indexPath.section):\(indexPath.row) did select")
    }
    
    func tableViewHandlerCellEvent(handlerIdentifier: String, cellIdentifier:String, eventIdentifier:String?, indexPath:IndexPath?, data: Any?, extra: Any?) {
        
        print("handler \(handlerIdentifier) cell \(cellIdentifier) event \(eventIdentifier ?? "")")
    }
}

如果您不喜欢大量的switch代码,则可以为每个事件标识符使用回调函数(或块)。

enum EventId: String {
    case thumbnailTouch
}

handler.registerCallback(callback: thumbnailTouch(indexPath:data:extra:), forCellIdentifier: TableViewCell.identifier(), withEventIdentifier: EventId.thumbnailTouch.rawValue)

extension ViewController {
    
    func thumbnailTouch(indexPath:IndexPath?, data:Any?, extra:Any?) {
        
        print("thumbnailTouch")
    }
}

您还可以使用回调函数(或块)不传递事件标识符以选择单元格事件。

handler.registerCallback(callback: tableViewCellSelectHandler(indexPath:data:extra:), forCellIdentifier: TableViewCell.identifier())

许可协议

仅适用MIT许可。更多信息请访问 http://en.wikipedia.org/wiki/MIT_License