ios - 如何使用 begin-endUpdates() 和多个自定义单元格展开/折叠 UITableViewCells?

标签 ios swift uitableview reloaddata

背景:单个 ViewController 包含 4 个自定义原型(prototype)单元。第一个始终可见,并且有一个 UITextField。 原型(prototype)单元 2、3 和 4 分别包含图像、标签和标签。但是,原型(prototype)单元 4 基于数组,可以有 1 行或多行,具体取决于第一个单元中的输入。

当在第一个单元格中输入某个字符串时,系统会检查是否存在在其属性之一中包含该字符串的对象。如果该值不正确,第一个单元格会更改高度和布局。如果值正确,第一个单元格会更改高度,最重要的是,其他 3 个原型(prototype)单元格会展开以显示与字符串输入相对应的对象的详细信息。如果用户输入另一个不正确的字符串,单元格就会折叠。

问题:对其他 3 个单元格的展开/折叠进行动画处理。我无法弄清楚如何定义 beginUpdates() 和 endUpdates() 之间的 numberOfRowsInSection() 方法和代码块(下面代码中的步骤 2)。即使没有 arraycells 实现,在 insertRows() 之后调用 reloadRows() 似乎也不起作用。

我尝试过的:

  • reloadData() = 正确显示数据,但我无法使用它,因为它不会提供必要的动画。
  • beginUpdates() 和 endUpdates() 之间没有任何内容 = 会出现以下错误:

    Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (6) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

我相信这与最后一个原型(prototype)单元基于数组这一事实有关,并且我没有重新加载单元的实际数据,而只是重新加载 View 。

  • 与 insertRowsAtIndexPath、reloadRowsAtIndexPath、... 的其他组合 = 会出现与行数相关的类似错误。

任何帮助将不胜感激!

简化代码:

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, updateUITableView {

    var people: [Person] = [
        Person(name: "name", image: "imagename1", description: "description1", children: ["name1","name2","name3"]),
        Person(name: "name2", image: "imagename3", description: "description2", children: ["name4", "name5", "name6"])
    ]

    enum Flag {
        case start
        case match
        case noMatch
    }
    var flag = Flag.start

    var globalObject: Person?

    @IBOutlet var tableView: UITableView!

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch (flag) {
        case .start :
            return 1
        case .noMatch:
            return 1
        case .match:
            return 3 + (globalObject?.children.count)! //PROBLEM!
        }
    }

    //START - Input received from tableViewCell
    func checkName(senderCell: SearchInputTableViewCell, name: String) {
        // STEP 1: Check if person exists
        let person = checkPersonNameMatch(nameInput: name)
        globalObject = person //save globally for cellForRowsAtIndexPath

        // STEP 2: Show/hide cells
        toggleCellsVisibility(person: person)
    }

    //STEP 1:
    func checkPersonNameMatch(nameInput: String) -> Person? {
        guard let index = people.index(where: {$0.name == nameInput}) else {
            flag = .noMatch
            return nil
        }
        let personFound = people[index]
        flag = .match
        globalObject = personFound
        return personFound
    }

    //STEP 2 = PROBLEM!
        func toggleCellsVisibility(person: Person?) {
    if person != nil { //Cells appear
        UIView.animate(withDuration: 0.7, animations: {

            self.tableView.beginUpdates()

            let indexPath: IndexPath = IndexPath(row: 1, section: 0) //for Image cell
            let indexPath2: IndexPath = IndexPath(row: 2, section: 0) //for Description cell
            //let indexPath3: IndexPath = IndexPath[....] //for array in Children cell

            self.tableView.insertRows(at: [indexPath], with: .bottom)
            self.tableView.insertRows(at: [indexPath2], with: .bottom)

            self.tableView.reloadRows(at: [indexPath], with: .bottom)
            self.tableView.reloadRows(at: [indexPath2], with: .bottom)
            //... a for-loop to reload the array cells here?

            self.tableView.endUpdates()
        })
    } else { //Cells disappear
        UIView.animate(withDuration: 0.4, animations: {
            self.tableView.beginUpdates()
            //... same code as above?
            self.tableView.endUpdates()
        })
    }
}

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch indexPath.row {
        case 0:
            let cellIdentifier = "InputCell"
            let inputCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputTableViewCell

            inputCell.delegate = self

            switch (flag) {
            case .start:
                self.tableView.rowHeight = 187
            case .match:
                self.tableView.rowHeight = 170
            case .noMatch:
                self.tableView.rowHeight = 200
            }

            return inputCell

        case 1:
            let cellIdentifier = "ImageCell"
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! ImageTableViewCell

            cell.image?.image = UIImage(named: (globalObject?.image)!)

            switch (flag) {
            case .start:
                self.tableView.rowHeight = 0
            case .match:
                self.tableView.rowHeight = 170
            case .noMatch:
                self.tableView.rowHeight = 0
            }

            return cell

        case 2:
            let cellIdentifier = "DescriptionCell"
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! DescriptionTableViewCell

            cell.description?.text = globalObject?.description

            switch (flag) {
            case .start:
                self.tableView.rowHeight = 0
            case .match:
                self.tableView.rowHeight = 54
            case .noMatch:
                self.tableView.rowHeight = 0
            }

            return cell

        default:
            let cellIdentifier = "ChildrenCell"
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! ChildrenTableViewCell

            cell.childName?.text = globalObject?.children[(indexPath as IndexPath).row - 3]

            switch (flag) {
            case .start:
                self.tableView.rowHeight = 0
            case .match:
                self.tableView.rowHeight = 44
            case .noMatch:
                self.tableView.rowHeight = 0
            }

            return cell
        }
    }
}

最佳答案

我的建议是:不要插入或删除这些行。只需将行始终保留在那里 - 高度为零(并将 clipsToBounds 设置为 true)。因此,在您需要它们之前,它们对用户来说是不可见的。当您需要它们时,只需更改高度并调用 beginUpdatesendUpdates

关于ios - 如何使用 begin-endUpdates() 和多个自定义单元格展开/折叠 UITableViewCells?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40307190/

相关文章:

clang - Swift:声明 'description' 不能覆盖多个父类(super class)声明

ios - UiTableView-将内容添加到相关部分

ios - 使用正则表达式提取两个标记之间的文本

ios - 'FBSDKAccessTokenDidChangeNotification' 的 swift 等价物是什么

html - 从 NSString 的 HTML 中检索内容

ios - Swift/iOS : Analyzing (lldb) crash, Paypal iOS SDK

ios - 如何使用自定义键盘 iOS 发送图像

ios - 使用 SpriteKit 检测 Sprite 边界框(alpha 蒙版)内的触摸

arrays - 我想从多个 tableView 选择创建一个数组

ios - 如何从 detailViewController 填充数组并返回到 iOS 中的 masterViewController?