You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView reloadData后UIView旋转动画失效问题求助

解决UITableView reloadData后旋转动画失效的问题

这个问题我之前碰到过类似的,核心是reloadData()会重置tableView头部视图的状态,再加上你原来的Core Animation动画方式存在状态持久化的问题,才导致动画在reload后失效。下面给你几个针对性的解决方案:

1. 替换Core Animation为UIKit动画,持久化视图状态

你原来用CABasicAnimation实现旋转,虽然设置了isRemovedOnCompletion = false和fillMode = kCAFillModeForwards,但这只是让layer显示动画后的状态,并没有真正修改视图的transform属性。当tableView reload时,视图的layer会被重置,之前的动画状态就丢失了。

改成UIKit的动画,它会在动画结束后自动更新视图的transform属性,状态是持久化的:

extension UIView {
    func rotate(_ toValue: CGFloat, duration: CFTimeInterval = 0.2) {
        UIView.animate(withDuration: duration) {
            self.transform = CGAffineTransform(rotationAngle: toValue)
        }
    }
}

2. 不要存储失效的Header实例,直接从TableView获取当前视图

你在viewForHeaderInSection里把每个dequeue出来的header都加到sectionHeaders数组里,但tableView的header是会被复用的,数组里的实例可能已经不是当前显示在界面上的那个了。调用旧实例的setExpanded自然看不到效果。

直接在需要操作的时候从tableView获取当前的header:

@objc func handleExpandClose(sender: UITapGestureRecognizer) {
    guard let section = sender.view?.tag else { return }
    // ... 其他代码 ...
    let isExpanded = menuItems[section].isExpanded
    menuItems[section].isExpanded = !isExpanded
    
    // 替换原来的sectionHeaders[section].setExpanded
    if let header = tableView.headerView(forSection: section) as? TableSectionHeader {
        header.setExpanded(expanded: !isExpanded)
    }
    
    // ... 插入/删除行的代码 ...
}

private func closeOpenedSections(section: Int) {
    var closeIndexPaths = [IndexPath]()
    for (sectionIndex, sec) in menuItems.enumerated() {
        guard let subItems = sec.subItems, sec.isExpanded, sectionIndex != section else { continue }
        sec.isExpanded = false
        // ... 收集indexPath的代码 ...
        
        // 替换原来的sectionHeaders[sectionIndex].setExpanded
        if let header = tableView.headerView(forSection: sectionIndex) as? TableSectionHeader {
            header.setExpanded(expanded: false)
        }
        tableView.deleteRows(at: closeIndexPaths, with: .fade)
    }
}

之后就可以删掉sectionHeaders数组了,避免维护失效的实例。

3. Reload时同步Header的初始状态

reloadData()会重新创建或复用header,所以要在viewForHeaderInSection里根据数据的isExpanded状态,设置header的初始旋转状态,确保reload后视图状态和数据一致:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if let sectionHeader = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "TableSectionHeader") as? TableSectionHeader {
        sectionHeader.setUpHeader(emphasize: menuItems[section].emphasize)
        sectionHeader.titleLabel.text = menuItems[section].title
        let tap = UITapGestureRecognizer(target: self, action: #selector(MenuTableViewController.handleExpandClose(sender:)))
        sectionHeader.addGestureRecognizer(tap)
        sectionHeader.indicatorImage.isHidden = menuItems[section].subItems != nil ? false : true
        sectionHeader.tag = section
        
        // 新增:根据当前展开状态设置初始旋转
        let isExpanded = menuItems[section].isExpanded
        sectionHeader.setExpanded(expanded: isExpanded)
        
        return sectionHeader
    }
    return UIView()
}

把这三个步骤结合起来,就能解决reloadData后动画失效的问题了。

内容的提问来源于stack exchange,提问作者Brudus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:56:17