swift: How to Flip Cell between two UITableViewCel

2019-08-17 06:00发布

I have two UITableViewCell in a UITableViewController.

I want to flip indexPaths on click didSelect method.

When I will click indextPath.row “0” in tableViewCellOne it will show indexPath.row “0” of tableViewCellTwo.

Now it is not flip properly. Also crash apps after click a few time on didSelect method.

Error message is:

//Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to dequeue multiple cells for the same index path, which is not allowed. If you really need to dequeue more cells than the table view is requesting, use the -dequeueReusableCellWithIdentifier: method (without an index path). Cell identifier: FlipTableViewCellZero, index path:

var isOpen = true

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

    if isOpen{

        let cell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellZero", for: indexPath) as! FlipTableViewCellZero

        var categoryObject = arrNewsList[indexPath.section]

        cell.profileImage = categoryObject[indexPath.row].textView
        return cell

    }else{

        let cell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellOne", for: indexPath) as! FlipTableViewCellOne

        var categoryObject = arrNewsList[indexPath.section]

        cell.newsTextView.text = categoryObject[indexPath.row].details

        return cell

    }
    return tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellZero", for: indexPath)

}


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    isOpen = true

    let selectedCell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellOne", for: indexPath) as! FlipTableViewCellOne
    UIView.transition(with: selectedCell, duration: 0.6, options: .transitionFlipFromLeft, animations: nil, completion: nil)
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    isOpen = false

    let deselectedCell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellZero", for: indexPath) as! FlipTableViewCellZero
    UIView.transition(with: deselectedCell, duration: 0.6, options: .transitionFlipFromLeft, animations: nil, completion: nil)
}

1条回答
唯我独甜
2楼-- · 2019-08-17 06:27

It looks like you want to display your category in two different ways: open and closed.

You're running into problems because you are trying to update the display by dequeueing a new cell in didSelectRowAt and didDeselectRowAt. This is incorrect.

The proper way to update the display is to call either:

  • tableView.reloadData, which reloads the entire table view, or
  • tableView.reloadRows(at:with:), which reloads just the specified rows

For simplicity, I'm going to use the first option in this example.

Another problem with your code is that you are trying to use a class-level variable isOpen to remember the state of your category. This isn't going to work when you have more than one category.

A better approach is to add isOpen as a property of your categoryObject class. You set it initially to false and then toggle it when the row is tapped. Here is a possible solution:

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

    let categoryObject = arrNewsList[indexPath.section]

    if categoryObject.isOpen {
        let cell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellZero", for: indexPath) as! FlipTableViewCellZero

        cell.profileImage = categoryObject[indexPath.row].textView
        return cell
    }
    else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "FlipTableViewCellOne", for: indexPath) as! FlipTableViewCellOne

        cell.newsTextView.text = categoryObject[indexPath.row].details
        return cell
    }
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {    
    let categoryObject = arrNewsList[indexPath.section]
    categoryObject.isOpen = true
    tableView.reloadData()
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    let categoryObject = arrNewsList[indexPath.section]
    categoryObject.isOpen = false
    tableView.reloadData()
}

Now, this doesn't give you the animation you wanted, but it addresses the core problem with your current code.

To do the animation, check into the documentation for reloadRows(at:with:). Using this method, instead of reloadData(), you can animate the change in display of your category.

查看更多
登录 后发表回答