Анимированное изменение макета с одновременным перекрестным растворением вида

У меня есть UIView содержащий ряд UILabel позиционируется с AutoLayout.

При повороте устройства я переключаю ограничения макета, чтобы анимировать метки в новые местоположения (ограничения макета выводятся из Layout объект, который присваивается виду):

override func viewWillTransition(
  to size: CGSize, 
  with coordinator: UIViewControllerTransitionCoordinator
) {
    super.viewWillTransition(to: size, with: coordinator)
    let isLandscape = size.width > size.height
    let layout = isLandscape ? layoutLandscape : layoutPortrait

    coordinator.animate(
        alongsideTransition: { _ in self.layoutView.setLayout(layout) },
        completion: nil
    )
}

Этот эффект хорошо работает и обеспечивает плавный переход между различными макетами контента, оптимизированными для альбомной и портретной ориентации.

Однако во время перехода размер меток также изменяется из-за ограничений макета. Заметно, что хотя переход позиций меток происходит постепенно, формы меток меняются сразу в начале перехода, а затем они анимируются до своей конечной позиции.

Я хотел бы иметь возможность перекрестного смещения меток между их начальной и конечной формами, чтобы это происходило вместе с анимацией положения.

В идеале, я хотел бы сделать это таким же образом, чтобы добиться анимации положения, когда код обновления макета не учитывает, будет ли изменение анимировано или нет. Я ожидаю, что хотя бы небольшой компромисс может потребоваться, хотя!

Спасибо.


Я довольно близок к рабочему решению по этому вопросу. Это еще не материал для ответов, поэтому я буду помещать здесь заметки как "Материал, который я пробовал" - если он станет ответом, я передам его одному.

Фантастическая статья на objc.io показывает, как вы можете создать UILabel подкласс, который скажет свою поддержку CALayer оживить изменения его content собственность с использованием CATransition, Это самое чистое волшебство, но на удивление оно имеет смысл, и вы подозреваете, что, возможно, вы тоже можете надеть шляпу волшебника.

Итак, вы получите что-то вроде этого:

class ContentAnimatedLabel: UILabel {
    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        guard event == "contents" else {
            return super.action(for: layer, forKey: event)
        }

        let transition = CATransition()
        // Oh noes! A hard coded made up value!
        // And where do we get the timing curve?! Curses.
        transition.duration = 0.3
        return transition
    }
}

И, насколько это возможно, это работает! Содержимое меток красиво выгорает, а их положение интерполируется. И это выглядит довольно грандиозно.

Проблема в том, что этот код не знает, вызывается ли он из блока анимации. Действительно, он должен возвращать переход только при вызове из блока анимации и должен копировать свойства анимации, такие как длительность и время, из свойств, заданных блоком анимации.

Статья предлагает решение этой проблемы...

Реализация механизма анимации UIView является закрытой, поэтому нет простого флага, который мы можем проверить, чтобы увидеть, анимируется ли в данный момент представление, однако мы знаем одно: при анимации actionForLayer: forKey: UIView будет возвращать действительные CAActions для своих ключей свойства анимации, и когда не анимируется, он вернет [NSNull null] для них. Если мы просто выберем подходящий ключ, мы можем запросить UIView, чтобы выяснить, предоставляет ли он в данный момент действие для этого ключа, и использовать его, чтобы определить наш ответ для нашего пользовательского ключа. Мы будем использовать ключ "backgroundColor", поскольку это свойство UIView, которое обычно поддерживает анимацию, и, как мы знаем, возвращает CABasicAnimation в качестве своего действия (начиная с iOS 8, некоторые свойства, такие как "bounds", вместо этого возвращают закрытый класс, так что следите)

… Но это, похоже, не работает, по крайней мере, для iOS 11, на котором я тестирую.

когда UIKit просит действия для content ключ, как будто блок анимации закончен. Запрашиваемая super действие, используемое другими ключами, всегда ничего не возвращает. Таким образом, у вас ничего не осталось, чтобы получить соответствующие параметры перехода.

0 ответов

Другие вопросы по тегам