背景:单个 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
)。因此,在您需要它们之前,它们对用户来说是不可见的。当您需要它们时,只需更改高度并调用 beginUpdates
和 endUpdates
。
关于ios - 如何使用 begin-endUpdates() 和多个自定义单元格展开/折叠 UITableViewCells?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40307190/