如何仅在TableView的特定Cell中显示和隐藏视图
Hey, I’ve run into this exact issue before with tall reusable cells—let’s fix this together! The root problem here is UITableView cell reuse: when cells scroll off-screen, they get recycled, and any UI state you set directly on the cell gets lost or overwritten when the cell is reused for another row. Since your data array is handling add/remove correctly, we just need to tie the UIView’s visibility state to your data model instead of storing it on the cell itself.
Here’s a step-by-step solution:
1. Add a state property to your data model
First, update your virtual item model (let’s call it VirtualItem for example) to track whether the inner UIView should be visible. This ensures the state is tied to the data, not the reusable cell:
struct VirtualItem { let name: String // Add this property to track visibility state var isDetailsViewVisible: Bool = false // Your other existing properties... }
2. Configure the cell using the model’s state
In your custom cell’s configuration method, use the model’s isDetailsViewVisible property to set the UIView’s visibility. This way, every time the cell is reused, it pulls the correct state from the data:
class CustomCell: UITableViewCell { @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var detailsView: UIView! @IBOutlet weak var toggleButton: UIButton! // Closure to handle button taps (cleaner than delegation for simple cases) var onToggleTapped: (() -> Void)? func configure(with item: VirtualItem) { nameLabel.text = item.name // Set visibility based on the model's state detailsView.isHidden = !item.isDetailsViewVisible // Optional: Update button title if needed (e.g. "Show" / "Hide") toggleButton.setTitle(item.isDetailsViewVisible ? "Hide Details" : "Show Details", for: .normal) } @IBAction func toggleButtonTapped(_ sender: UIButton) { onToggleTapped?() } }
3. Handle button taps and refresh the cell
In your table view’s cellForRowAt method, assign the closure to update the model’s state and refresh only the affected cell (avoid reloading the entire table, which can cause unwanted scrolling):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as? CustomCell else { return UITableViewCell() } let item = yourItemsArray[indexPath.row] cell.configure(with: item) cell.onToggleTapped = { [weak self] in guard let self = self else { return } // Toggle the state in your data array self.yourItemsArray[indexPath.row].isDetailsViewVisible.toggle() // Add/remove the item from your tracking array (you said this part works already) if self.yourItemsArray[indexPath.row].isDetailsViewVisible { self.selectedItemsArray.append(item) } else { if let index = self.selectedItemsArray.firstIndex(of: item) { self.selectedItemsArray.remove(at: index) } } // Refresh ONLY the tapped cell to preserve scroll position and avoid reuse issues tableView.reloadRows(at: [indexPath], with: .automatic) } return cell }
4. Bonus: Ensure dynamic cell heights work correctly
Since your cells are very tall, make sure your table view is set up to handle dynamic heights properly (if you haven’t already):
override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 800 // Set a value close to your average cell height }
Why this works
By storing the visibility state in your data model instead of the cell, you ensure that every time the cell is reused (even after scrolling), it loads the correct state from the model. Reloading only the specific cell keeps the user experience smooth without resetting the table’s scroll position.
内容的提问来源于stack exchange,提问作者Tigran Iskandaryan

