记录一次树形分级列表的实现

实现思路

使用 tableView 实现先树形结构(不同的 cell 样式显示不同的等级),当点击 cell 时,判断当前点击的 cell 是否存在下一级,是否已经是打开状态.如果存在下一级,关闭状态,则通过插入 cell 实现点击展开树形图的效果.如果存在下一级且已经展开则通过删除 cell的方式实现树形图的关闭效果.

具体实现

  1. 定义数据结构类型,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class YTTTreeListModel: NSObject {

    /**
    你所需要的属性
    var name: String = ""
    var address: String = ""
    var age: Int = -1
    ...
    **/

    // 当前节点是否有下一级
    var isShow: Bool = false
    // 当前节点是否展开
    var isOpen: Bool = false
    // 当前的等级
    var level: Int = 0
    // 当前节点的子节点
    var child: [QWMyTeamModel] = []
    }
  2. 定义主要的方法(递归算法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    /// 获取 cell 的行数
    ///
    /// - Parameter items: 数据源
    /// - Returns: cell 行数
    private func getRowsNum(_ items: [YTTTreeListModel]) -> Int {
    var num = 0
    items.forEach { (model) in
    num += 1
    if model.isShow && model.isOpen && model.child.count > 0 {
    num += getRowsNum(model.child)
    }
    }
    return num
    }

    /// 获取当前 cell 的数据模型
    ///
    /// - Parameters:
    /// - items: 数据源
    /// - index: 当前位置
    /// - Returns: 数据模型
    private func getItem(_ items: [YTTTreeListModel], index: inout Int) -> YTTTreeListModel? {

    for item in items {
    if index == 0 {
    return item
    }
    index -= 1
    if item.isShow && item.isOpen && item.child.count > 0 {
    if let model = getItem(item.child, index: &index) {
    return model
    }
    }
    }
    return nil
    }

    /// 获取需要添加或删除的 cell
    ///
    /// - Parameters:
    /// - item: 当前数据模型(点击的 cell)
    /// - index: 当前位置
    /// - Returns: 需要删除或添加位置
    private func getIndexPath(_ item: YTTTreeListModel, index: inout Int) -> [IndexPath] {
    var indexPaths: [IndexPath] = []
    for item in item.child {
    index += 1
    indexPaths.append(IndexPath(row: index, section: 0))
    if item.isShow && item.isOpen && item.child.count > 0 {
    indexPaths.append(contentsOf: getIndexPath(item, index: &index))
    }
    }
    return indexPaths
    }
  3. 实现代理方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    // dataArr     private var dataArr: [YTTTreeListModel] = []

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return getRowsNum(dataArr)
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    var index = indexPath.row
    if let model = getItem(dataArr, index: &index) {
    if model.level == 1 {
    // 返回第一级样式
    } else if model.level == 2 {
    // 返回第二级样式
    }else if model.level == 3 {
    // 返回第三级样式
    }
    ...
    }
    return UITableViewCell()
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    var index = indexPath.row
    if let model = getItem(dataArr, index: &index) {

    if model.isOpen {
    tableView.beginUpdates()
    model.isOpen = false
    var ind = indexPath.row
    tableView.reloadRows(at: [indexPath], with: .none)
    tableView.deleteRows(at: getIndexPath(model, index: &ind), with: .none)
    tableView.endUpdates()
    }else {
    if !model.isShow {
    return
    }

    // 存在下一级且子级已经加载直接展开
    if model.isShow == 1 && model.child.count > 0 {
    tableView.beginUpdates()
    model.isOpen = true
    var ind = indexPath.row
    tableView.reloadRows(at: [indexPath], with: .none)
    tableView.insertRows(at: getIndexPath(model, index: &ind), with: .none)
    tableView.endUpdates()
    }else {
    // 存在下一级,但数据未请 求网络请求
    http.globalPOST(url: **, parameters: ["": ""], success: { [weak self] (result) in
    if let models = YTTTreeListModel(dictArray: result) as? [YTTTreeListModel] {
    model.child = models.compactMap({ (item) -> YTTTreeListModel in
    item.level = model.level + 1 // 设置等级
    return item
    })
    tableView.beginUpdates()
    model.isOpen = true
    var ind = indexPath.row
    tableView.reloadRows(at: [indexPath], with: .none)
    if let indexs = self?.getIndexPath(model, index: &ind) {
    tableView.insertRows(at: indexs, with: .none)
    }
    tableView.endUpdates()
    }

    }, fail: {(error) in

    }, isHUD: true)
    }
    }
    }
    }