swift中实现多级列表数结构显示

▼魔方 西西 提交于 2020-08-06 03:13:36

在程序开发过程中,常会遇到多级数据结构的显示,大多数情况下都是二级或三级的情况,这时候用UITableview的基本用法就可以解决此类问题。但是,有时候后若是有四级五级...,普通的使用方法就不是好了,之前我就遇到过了很多级的数据结构显示问题,在这里记录一下

因为我的数据量不是很大,才这样弄的,至于数据过大过多是,大家还是自己看着用吧😂

我这里还是用的UITableview,显示的问题是通过对数据本身的操作来完成,简而言之就是在数据中添加一个标记(type:用于显示其结构等级),然后在cell中根据该标记(type),做出相应的显示以区别。

由于显示的数据类型有很多,为避免在多个model中重复书写相同逻辑代码,也为了使用其通用性更好,我使用了协议的方式,下边是我的主要代码

import Foundation

///用于构造多级树
@objc protocol HZJTreeViewModelProtocol {
    /// 所属父数据(不用手动去设置,会根据setChildModels自动修改)
    var fatherModel:HZJTreeViewModelProtocol? { get set }
    
    /// 包含的子数据(需使用setChildModels方法赋值)
    var childModels:[HZJTreeViewModelProtocol] { get set }
}

//MARK: - 添加的非私有属性
extension HZJTreeViewModelProtocol {
    /// 是否展示当前项
    public var isShowCurrent:Bool {
        return self._isShow
    }

    /// 是否打开,以展示当前项的childModels
    public var isOpen:Bool {
        return self._isOpen
    }
    
    ///等级
    var type:Int{
        return self._type
    }
}

//MARK: -用于修改属性的方法
extension HZJTreeViewModelProtocol {
    @discardableResult
    public func toShowCurrent(_ show:Bool) -> HZJTreeViewModelProtocol{
        self._isShow = show
        return self
    }
    
    @discardableResult
    public func setOpenState(_ open:Bool) -> HZJTreeViewModelProtocol{
        self._isOpen = open
        return self
    }
}

//MARK: -其他重要的方法
extension HZJTreeViewModelProtocol {
    /// 设置子数据(注意不要循环引用了)
    /// - Parameter models: <#models description#>
    /// - Returns: <#description#>
    @discardableResult
    public func setChildModels(_ models:[HZJTreeViewModelProtocol]) -> [HZJTreeViewModelProtocol] {
        for item in models {
            item.fatherModel = self
            item._isShow = self.isOpen
        }
        self.childModels = models
        self.setAllChildModeType(self._type)
        return self.childModels
    }
    
    /// 修改当前childModels的展示状态
    /// - Parameter open: 是否展示
    /// - Parameter allChild: 是否针对所有子数据
    public func changeChildModelShowState(_ open:Bool, allChild:Bool = false) {
        self._isOpen = open
        for item in self.childModels {
            item._isShow = open
            if allChild {
                item.changeChildModelShowState(open, allChild: allChild)
            }
        }
    }
    
    /// 获取所有子数据(包括子数据的子数据的子数据...递归操作)
    /// - Returns: <#description#>
    public func getAllChildModel() -> [HZJTreeViewModelProtocol] {
        var result:[HZJTreeViewModelProtocol] = []
        for item in self.childModels {
            result.append(item)
            result.append(contentsOf: item.getAllChildModel())
        }
        return result
    }
    
    /// 获取需要展示所有子数据(包括子数据的子数据的子数据...递归操作,若父类 关闭,则不向下遍历)
    /// - Returns: <#description#>
    public func getAllShowChildModel() -> [HZJTreeViewModelProtocol] {
        var result:[HZJTreeViewModelProtocol] = []
        for item in self.childModels {
            if item.isShowCurrent {
                result.append(item)
            }
            if item._isOpen {
                result.append(contentsOf: item.getAllShowChildModel())
            }
        }
        return result
    }
}

//MARK: - 私有属性
private extension HZJTreeViewModelProtocol {
    /// 是否展示当前项
    var _isShow:Bool {
        set {
            objc_setAssociatedObject(self, AssociationKey.from(#function), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            guard let t = objc_getAssociatedObject(self,  AssociationKey.from(#function)) as? Bool else {
                return true//默认值
            }
            return t
        }
    }
    
    /// 是否打开,以展示当前项的childModels
    var _isOpen:Bool {
        set {
            objc_setAssociatedObject(self, AssociationKey.from(#function), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            guard let t = objc_getAssociatedObject(self,  AssociationKey.from(#function)) as? Bool else {
                return false//默认值
            }
            return t
        }
    }
    
    ///等级
    var _type:Int {
        set {
            objc_setAssociatedObject(self, AssociationKey.from(#function), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            guard let t = objc_getAssociatedObject(self,  AssociationKey.from(#function)) as? Int else {
                return 1//默认值
            }
            return t
        }
    }
}

//MARK: - 私有的方法
private extension HZJTreeViewModelProtocol{
    
    /// 递归设置子数据的type
    func setAllChildModeType(_ currentType:Int){
        for item in self.childModels {
            let type =  currentType + 1
            item._type = type
            item.setAllChildModeType(type)
        }
    }
}


使用时,需要数据遵循该协议

/// 数据模型,遵循HZJTreeViewModelProtocol就好
class HZJTreeModel: HZJTreeViewModelProtocol  {
    
    var fatherModel: HZJTreeViewModelProtocol?
    
    var childModels: [HZJTreeViewModelProtocol] = []
    
    /// 自定义的属性
    var titleInfo: String = ""
    
    /// 自定义便捷构造器
    init(_ titleInfo:String) {
        self.titleInfo = titleInfo
    }
}

最后再cell中通过model中的type属性来区别显示

当然这里还有折叠/展示等逻辑,我就不再赘述,有兴趣的小伙伴可以看以我这个简单的代码,其实挺简单的😁

再来个运行想过图吧

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!