Анимация UIView в UITableView не работает после перезагрузки данных

Я столкнулся со странной ошибкой в ​​​​своем приложении прямо сейчас. У меня есть расширение для UIView, которое поворачивает индикатор на 90 градусов влево и вправо. Я использую UITableViewController в качестве навигационного ящика. Я также добавил расширяемый список и использовал UITableViewHeaderFooterView для основных областей (у которых есть подэлементы).

UITableViewHeaderFooterView похож на основные «ячейки». А под ними реальные ячейки UITableView, которые удаляются и вставляются, когда пользователь нажимает на UITableViewHeaderFooterView.

В зависимости от URL-адреса, который имеет WebView (основной вид), я хочу обновить содержимое tableView. Как только данные изменяются, анимация расширения перестает работать. Код по-прежнему выполняется, и значения верны. Я просто больше не вижу анимацию.

UITableViewHeaderFooterView:

import UIKit

class TableSectionHeader: UITableViewHeaderFooterView {
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var containerView: UIView!
    @IBOutlet weak var indicatorImage: UIImageView!

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        indicatorImage.image = IconFont.image(fromIcon: .next, size: Constants.Sizes.MENU_INDICATOR_SIZE, color: Constants.Colors.WHITE_COLOR)
    }

    func setExpanded(expanded: Bool) {
        indicatorImage.rotate(expanded ? .pi / 2 : 0.0)
    }
}

Метод внутри WebViewController:

private func loadNewMenu(href: String) {
    NetworkService.sharedInstance.getNavigation(path: href, completion: { menu in
        if let menuController = self.menuVC {
            menuController.menuItems = menu
            menuController.tableView.reloadData()
        }
    })
 }

Расширение UIView:

import UIKit

extension UIView {

    func rotate(_ toValue: CGFloat, duration: CFTimeInterval = 0.2) {
        let animation = CABasicAnimation(keyPath: "transform.rotation")

        animation.toValue = toValue
        animation.duration = duration
        animation.isRemovedOnCompletion = false
        animation.fillMode = kCAFillModeForwards

        self.layer.add(animation, forKey: "rotationIndicator")
    }

}

Соответствующие методы для MenuTableViewController:

// MARK: Custom Menu Methods

@objc func handleExpandClose(sender: UITapGestureRecognizer) {        
    guard let section = sender.view?.tag else {
        return
    }

    var indexPaths = [IndexPath]()

    for row in subItems.indices {
        let indexPath = IndexPath(row: row, section: section)
        indexPaths.append(indexPath)
    }

    let isExpanded = menuItems[section].isExpanded
    menuItems[section].isExpanded = !isExpanded
    sectionHeaders[section].setExpanded(expanded: !isExpanded)

    if isExpanded {
        tableView.deleteRows(at: indexPaths, with: .fade)
    } else {
        tableView.beginUpdates()
        closeOpenedSections(section: section)
        tableView.insertRows(at: indexPaths, with: .fade)
        tableView.endUpdates()
    }
}

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
        for rowIndex in subItems.indices {
            let closeIndexPath = IndexPath(row: rowIndex, section: sectionIndex)
            closeIndexPaths.append(closeIndexPath)
        }

        sectionHeaders[sectionIndex].setExpanded(expanded: false)

        tableView.deleteRows(at: closeIndexPaths, with: .fade)
    }
}

Это реализация viewForHeaderInSection в моем MenuTableViewController:

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
        self.sectionHeaders.append(sectionHeader)

        return sectionHeader
    }

    return UIView()
}

Я знаю, что это много кода, но я думаю, что это как-то связано с reloadData() tableView. Анимация работает отлично, прежде чем я выполню перезагрузку. Если я не открыл меню до его перезагрузки, я также не вижу ошибки. Это просто происходит после первой перезагрузки данных (даже если данные точно такие же).

Опять же, код анимации все еще выполняется, и расширенное значение является правильным (true/false). Я напечатал UIImageView, на котором происходит анимация, на консоль, и кажется, что это идентичное представление даже после перезагрузки. Но анимация не появляется.


person Brudus    schedule 29.01.2018    source источник
comment
Если вы не вызываете .reloadData(), можете ли вы запустить анимацию снова?   -  person DonMag    schedule 29.01.2018
comment
@DonMag Ну да, это все еще работает. Но данные тоже не обновляются.   -  person Brudus    schedule 29.01.2018
comment
Я мало что сделал с CABasicAnimation, так что просто выскажу мысль... Нужно ли вызывать .removeAnimation(forKey:) перед повторной анимацией?   -  person DonMag    schedule 29.01.2018
comment
@DonMag Я тоже сначала так подумал. Но я добавил цикл forEach, который удаляет все анимации перед перезагрузкой, и он не работает :/   -  person Brudus    schedule 29.01.2018
comment
Хммм... похоже, вы вызываете .reloadData() из блока завершения. Это работает в основном потоке? Мне стоит попытаться обернуть это в блок DispatchQueue.main.async() и/или убедиться, что вы вызываете indicatorImage.rotate(...) в основном потоке.   -  person DonMag    schedule 29.01.2018
comment
Спасибо за вашу помощь, но это все еще не работает :/ Странно то, что ничего не работает. Код работает, как и ожидалось, но функция поворота по-прежнему не видна (но все равно вызывается правильно). Я ожидал, что это будет проблема с TapGestureRecognizer, и мне нужно было его удалить. Но он уже вызывается только один раз. Это не должно быть проблемой.   -  person Brudus    schedule 29.01.2018
comment
Просто выбрасываю еще одну идею... Вызвать .setNeedsDisplay() в заголовке?   -  person DonMag    schedule 29.01.2018
comment
Нет, к сожалению, не работает :/   -  person Brudus    schedule 29.01.2018
comment
МОЙ БОГ! Я нашел ошибку. Была ли ошибка программиста моей. Количество ячеек рассчитывается по количеству пунктов меню. Однако количество sectionHeaders никогда не уменьшается до нуля, поэтому будет вызван совершенно другой номер раздела (который не виден).   -  person Brudus    schedule 29.01.2018
comment
О! Рад, что ты нашел это.   -  person DonMag    schedule 29.01.2018


Ответы (1)


Оказалось, что это моя ошибка! Я использовал два массива (sectionHeaders, menuItems). Я изменил только один из них, когда получил новые данные. Поэтому возникло несоответствие между ячейками и содержимым, над которым я работал.

person Brudus    schedule 02.02.2018