快速!简单!便捷!得!使用UITableView和UICollectionView

对于实现一个列表视图,使用苹果官方的方式真是恶心的不行,要实现多个代理,还要复写多个名字一样,参数名不同还很长的函数,真真的是写不下去的。。。

然后,依据android的adapter,弄了个swift版的Adapter类,方便的实现这一切,先看使用方法

简单使用

实现一个简单的UICollectionView列表视图:

class MyMolde{
    //数据model
}
class MyViewCell: UICollectionViewCell {
    //创建Cell布局
}
//创建一个 adapter 类,传入泛型 model 和 cell
class MyAdapter: BaseQuickAdapter<MyMolde,MyViewCell> {
    //cell大小
    override func cellSize(data:MyMolde, indexPath:IndexPath) ->CGSize{
        CGSize(width:ScreenWidth, height:PT_100)
    }
    override func bindView(data:MyMolde, indexPath:IndexPath, cell:MyViewCell) {
        //将model的数据显示到cell上面
    }
}
复制代码

然后绑定:

        let mCollectionView = UICollectionView(frame: .zero ,collectionViewLayout: UICollectionViewFlowLayout())
        let mAdapter = MyAdapter()
        //绑定collectionView 和 adapter
        mCollectionView.setAdapter(mAdapter)
复制代码

完事收工!!!

进阶使用

        mAdapter.setOnItemSelected { (indexPath, model) in
            //处理点击事件
        }
        mAdapter.setOnItemLongPress { (indexPath, model) in
            //处理长按事件
            
            //移除数据
            mAdapter.removeItem(indexPath)
        }
        //设置数据
        let data = [MyMolde(),MyMolde(),MyMolde()]
        mAdapter.setNewData(data)
        //添加数据
        mAdapter.appendData(MyMolde())
        //获取adapter的数据
        let dataArray = mAdapter.getData()
复制代码

使用多个cell布局

同样非常的简单


//数据model 实现 CellType 协议,根据cellType属性区分要使用的cell类型,cellType即注册cell时使用的标识
class MyMolde:CellType{
    static let TYPE_1 = "1"
    static let TYPE_2 = "2"
    
    //根据不同的布局设置不同的type
    var cellType: String = TYPE_1
}
class MyViewCell: UICollectionViewCell {
    //创建Cell布局
}
class MyViewCell2: UICollectionViewCell {
    //创建Cell布局
}
//创建一个 adapter 类
class MyAdapter: BaseAdapter<MyMolde> {
    override init() {
        super.init()
        //注册cell
        registerCell(MyViewCell.self, MyMolde.TYPE_1)
        registerCell(MyViewCell2.self, MyMolde.TYPE_2)
    }
    //cell大小
    override func cellSize(data: MyMolde, indexPath: IndexPath) -> CGSize {
        //根据data.cellType 设置不同的size
        if data.cellType == MyMolde.TYPE_1 {
            return CGSize(width: ScreenWidth, height: PT_100)
        }else if data.cellType == MyMolde.TYPE_2{
            return CGSize(width: ScreenWidth, height: PT_200)
        }
        return .zero
    }
    override func bindView(data: MyMolde, indexPath: IndexPath, collectionCell: UICollectionViewCell) {
        //将model的数据显示到cell上面
        
        //根据data.cellType 转换成不同的 cell
        if data.cellType == MyMolde.TYPE_1 {
            let cell = collectionCell as! MyViewCell
        }else if data.cellType == MyMolde.TYPE_2{
            let cell = collectionCell as! MyViewCell2
        }
    }
}
复制代码

目前就弄了这点功能,如果有使用到其他功能,后期再加。
初学者,代码比较简陋随意O(∩_∩)O,欢迎指正!

BaseAdapter源码:

//
//  BaseAdapter.swift
//  bookista
//
//  Created by DU on 2021/4/25.
//

import Foundation

let DefaultCellId = "BaseCell" //默认的cellId

class BaseAdapter<T> :NSObject,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UITableViewDelegate,UITableViewDataSource{
    
    private var mData = [T]()//数据列表
    private var mCell = [String:AnyClass?]() //需要注册的cell
    private var onItemSelected:((IndexPath,T)->Void)? //点击事件
    private var onItemLongPress:((IndexPath,T)-> Void)? //长按事件
    
    private var mCollectionView:UICollectionView?
    private var mTableView:UITableView?
    
    /**
     绑定 UICollectionView
     */
    func bindTo(_ collectionView: UICollectionView){
        if mTableView != nil || mCollectionView != nil {
            fatalError("已经绑定过 UITableView 或 UICollectionView")
        }
        mCollectionView = collectionView
        mCollectionView?.delegate = self
        mCollectionView?.dataSource = self
        mCell.forEach { (cell) in
            mCollectionView?.register(cell.value, forCellWithReuseIdentifier: cell.key)
        }
    }
    /**
     绑定 UITableView
     */
    func bindTo(_ tableView: UITableView){
        if mTableView != nil || mCollectionView != nil{
            fatalError("已经绑定过 UITableView 或 UICollectionView")
        }
        mTableView = tableView
        mTableView?.delegate = self
        mTableView?.dataSource = self
        mCell.forEach { (cell) in
            mTableView?.register(cell.value, forCellReuseIdentifier: cell.key)
        }
    }
    
    /**
     获取数据
     */
    func getData() -> [T]{
        return mData
    }
    /**
     设置新的数据
     */
    func setNewData(_ data:[T]){
        mData.removeAll()
        mData.append(contentsOf: data)
        mCollectionView?.reloadData()
        mTableView?.reloadData()
    }
    /**
     添加数据
     */
    func appendData(_ data:T){
        mData.append(data)
        mCollectionView?.reloadData()
        mTableView?.reloadData()
    }
    
    /**
     注册cell - 用于不用样式的cell注册
     reuseIdentifier = model.cellType
     */
    func registerCell(_ cell:AnyClass?,_ reuseIdentifier: String){
        mCell.updateValue(cell, forKey: reuseIdentifier)
    }
    /**
     注册cell - 只有一种样式
     */
    func registerCell(_ cell:AnyClass?){
        self.registerCell(cell, DefaultCellId)
    }
    
    /**
     item 点击
     */
    func setOnItemSelected(_ onItemSelected:((IndexPath,T)->Void)?){
        self.onItemSelected = onItemSelected
    }
    
    /**
     设置长按点击事件
     */
    func setOnItemLongPress(_ todo: ((IndexPath,T)-> Void)?){
        self.onItemLongPress = todo
        let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressGesture(_:)))
        self.mCollectionView?.addGestureRecognizer(recognizer)
        self.mTableView?.addGestureRecognizer(recognizer)
    }
    
    //长按动作
    @objc func longPressGesture(_ tap: UILongPressGestureRecognizer) {
        if tap.state == .began {
            if mTableView != nil {
                guard let path = mTableView!.indexPathForRow(at: tap.location(in: mTableView!)) else {
                    return
                }
                self.onItemLongPress?(path,mData[path.row])
            }else if mCollectionView != nil {
                guard let path = mCollectionView!.indexPathForItem(at: tap.location(in: mCollectionView!)) else {
                    return
                }
                self.onItemLongPress?(path,mData[path.item])
            }
        }
    }
    /**
     移除cell
     */
    func removeItem(_ indexPath:IndexPath){
        if mCollectionView != nil {
            mData.remove(at: indexPath.item)
            mCollectionView?.deleteItemsAtIndexPaths([indexPath], animationStyle: .automatic)
        }else if mTableView != nil {
            mData.remove(at: indexPath.row)
            mTableView?.deleteItemsAtIndexPaths([indexPath], animationStyle: .automatic)
        }
    }
    
    
    //MARK:  UITableView =========================================================
    
    /**
     设置view显示内容 - UITableViewCell
     */
    func bindView(data:T, indexPath: IndexPath, tableCell:UITableViewCell){
        
    }
    /**
     table cell height
     */
    func cellHeight(data:T, indexPath: IndexPath) -> CGFloat{
        return 100
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        mData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cellId = DefaultCellId
        if T.self is CellType {
            cellId = (mData[indexPath.row] as! CellType).cellType
        }
//        let cellId = mData[indexPath.row].cellType
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        self.bindView(data: mData[indexPath.row], indexPath: indexPath, tableCell: cell)
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.onItemSelected?(indexPath,mData[indexPath.row])
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellHeight(data: mData[indexPath.row], indexPath: indexPath)
    }
    
    
    
    //MARK:  UICollectionView =========================================================
    
    /**
     设置view显示内容 - UICollectionViewCell
     */
    func bindView(data:T, indexPath: IndexPath, collectionCell:UICollectionViewCell){
        
    }
    /**
     cell size
     */
    func cellSize(data:T, indexPath: IndexPath) -> CGSize{
        return .zero
    }
    /**
     行间距
     */
    func lineSpace() -> CGFloat{
        0
    }
    /**
     左右间距
     */
    func interitemSpace() -> CGFloat{
        0
    }
    /**
     section 边距
     */
    func sectionInset() -> UIEdgeInsets {
        .zero
    }
    
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        mData.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        var cellId = DefaultCellId
        if T.self is CellType {
            cellId = (mData[indexPath.item] as! CellType).cellType
        }
//        let cellId = mData[indexPath.item].cellType
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
        self.bindView(data: mData[indexPath.item], indexPath: indexPath, collectionCell: cell)
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        self.onItemSelected?(indexPath,mData[indexPath.item])
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return cellSize(data:mData[indexPath.item],indexPath: indexPath)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return lineSpace()
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return interitemSpace()
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInset()
    }
    
}
//MARK:  BaseQuickAdapter =================================

/**
 快速创建一个单样式的adapter
 */
class BaseQuickAdapter<Model,ViewCell:UIView>: BaseAdapter<Model> {
    override init() {
        super.init()
        registerCell(ViewCell.self)
    }
    func bindView(data: Model, indexPath: IndexPath, cell: ViewCell){
        
    }
    override func bindView(data: Model, indexPath: IndexPath, tableCell: UITableViewCell) {
        self.bindView(data: data, indexPath: indexPath, cell: tableCell as! ViewCell)
    }
    override func bindView(data: Model, indexPath: IndexPath, collectionCell: UICollectionViewCell) {
        self.bindView(data: data, indexPath: indexPath, cell: collectionCell as! ViewCell)
    }
}

//MARK:  ===============================================
extension UICollectionView {
    func setAdapter<T>(_ adapter:BaseAdapter<T>){
        adapter.bindTo(self)
    }
}

extension UITableView {
    func setAdapter<T>(_ adapter:BaseAdapter<T>){
        adapter.bindTo(self)
    }
}
/**
 实现不同布局的cell,使model类实现此协议
 */
protocol CellType{
    /**
     注册cell时的 ReuseIdentifier
     */
    var cellType:String{get set}
}

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享