The project needs to display the users in a tree structure according to the different referees. Use tableView to do this.

Implementation approach

Use tableView to realize the tree structure (different cell styles show different levels). When clicking the cell, judge whether the current clicked cell has the next level and whether it has been opened. If the next-level, off state exists, click to expand the tree by inserting the cell. If the next level exists and has been expanded, the tree graph can be closed by deleting cells.

The specific implementation

  1. Define the data structure type as follows:
class YTTTreeListModel: NSObject {
    
    Var name: String = "" var address: String = "" var age: Int = -1... * * /
    
    // Whether the current node has a next level
    var isShow: Bool = false
    // Whether the current node is expanded
    var isOpen: Bool = false
    // The current level
    var level: Int = 0
    // Children of the current node
    var child: [QWMyTeamModel] = []}Copy the code
  1. Define the main method (recursive algorithm)
/// Get the number of cell lines
///
/// -parameter items: data source
/// - Returns: Number of cell rows
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
}

// get the data model of the current cell
///
/// - Parameters:
/// -items: data source
/// -index: indicates the current position
/// - Returns: data model
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
}

/// Obtain the cell to be added or deleted
///
/// - Parameters:
/// -item: current data model (click cell)
/// -index: indicates the current position
/// - Returns: A location needs to be deleted or added
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
}
Copy the code
  1. Implementing proxy methods
// 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 {
            // returns the first level of style
        } else if model.level == 2 {
            // Returns the second-level style
        }else if model.level == 3 {
            // Return the third level style}... }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
            }
            
            // The next level exists and the children are already loaded
            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 {
            // The next level exists, but the data is not requested by the network
            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 // Set the level
                        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)}}}}Copy the code