简体   繁体   中英

How to animate UIStackView hiding inside UITableViewCell properly?

I want to animate the subviews of the TableViewCell which is StackView. When I hide the StackView, the TableViewCell height not updating. After googling, I found that I should call tableView.beginUpdates and tableView.endUpdates to notify tableView that there is a change in the cell. The problem is the hide animation and the change of tableview not sync.

Here is the view hierarchy for tableview cell

Content view - Container View (for card shadow) - Container Stack View - [Stack View for label and switch] & [StudentStackView for container of StudentView]

How can I sync the cell height and hide animation the correct way?

Here is the github repo: GitHub

Gif of the App: UIStackView 动画与单元格高度不同步

You are right in using beginUpdates()/endUpdates() . Make sure you're not placing the someArrangedSubview.isHidden = true/false in an animate block since the table view and stack view will handle the animations accordingly. When the table view begins update operations, the stack view will resize any arranged subviews that you aren't removing to fill the entire space of the cell (even if you have height constraints on the arranged subview). In my case, the cell content jumped every time I wanted to collapse a cell via removing an arranged subview--so I added a dummy view between the view I wished to remain static* and the collapsible view. The static view won't resize, and the dummy view will expand/collapse as needed. Hope this helps.

*static in the sense that I didn't want the view to move when animating.

 `public func setup(classRoom: ClassRoom, toggleInProcess: @escaping () -> (), toggled: @escaping () -> ()) {
        containerStackView.addArrangedSubview(studentStackView)
        self.nameLabel.text = classRoom.name
        self.activeSwitch.isOn = classRoom.isActive
        self.studentStackView.isHidden = !self.activeSwitch.isOn // Let him know his hide/unhide. 
        for student in classRoom.students {
            let studentView = StudentView()
            studentView.nameLabel.text = student.name
            studentStackView.addArrangedSubview(studentView)
        }
        activeSwitch.addTarget(self, action: #selector(toggleShowStudents(show:)), for: .valueChanged)
        self.toggleInProcess = toggleInProcess
        self.toggled = toggled
        setupShadow()
    }`


`  @objc func toggleShowStudents(show: Bool) {
        UIView.animate(withDuration: 0.3, animations: {
            self.studentStackView.isHidden = !self.activeSwitch.isOn
            self.toggleInProcess()
            self.containerView.layoutIfNeeded()
        }) { _ in
            self.toggled()
        }
    }`

your studentStackView also know his hide/unhide status while assigning values in function setup .

I left this as a comment but for anyone else experiencing this behavior, the root cause is the UILabel is expanding to fill the visible area before collapsing.

This can be fixed by doing the following 2 things:

  1. Right below the UILabel, insert a Blank UIView
  2. Adjust the Content Hugging Priority of the UILabel to "Required"

With these two adjustments, instead of the UILabel expanding to fill the visible area, the UIView expands instead. Visually, this appears as if the the cell just collapses.

tableView.beginUpdates and tableView.endUpdates are functions that should be called when you are about to modify rowcount or selected state of the rows.

You should try reloadData or reloadrowsatindexpaths , that should take care of the cell height adjustment.

You would better do it using performSelector API so as not to cause recursion in cellForRowAt call stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM