Анимация ограничений автоматического макета с помощью NSView.layoutSubtreeIfNeeded() не работает на MacOS High Sierra

У меня есть базовое приложение Mac с анимацией представления, выполненной с помощью Auto Layout:

  • Я добавляю новый вид справа от текущего вида
  • Я обновляю ограничения так, чтобы новый вид заканчивал тем, что заполнил окно

→ Анимация будет выглядеть так, как будто вид скользит справа.

Рекомендуемый способ анимации изменений Auto Layout:

  1. Обновите ограничения
  2. использование NSAnimationContext.runAnimationGroup()
  3. Задавать allowsImplicitAnimation в true внутри блока анимации
  4. Вызов view.layoutSubtreeIfNeeded() внутри блока анимации

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

Я нашел обходной путь: я планирую анимацию на следующий цикл запуска, используя DispatchQueue.main.async, Тем не менее, это похоже на взлом, и мне интересно, есть ли что-то еще, что я здесь скучаю.

Вот мой фактический код:

private func appendSlideViewControllerAnimated(_ viewController:NSViewController, to viewToTheLeft:NSView)
{
    // Insert the new view on the very right, just outside the parent:

    viewController.view.frame = self.view.bounds
    viewController.view.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(viewController.view)

    viewController.view.topAnchor.constraint(     equalTo: view.topAnchor     ).isActive = true
    viewController.view.bottomAnchor.constraint(  equalTo: view.bottomAnchor  ).isActive = true

    viewController.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

    viewController.view.leadingAnchor.constraint(equalTo: viewToTheLeft.trailingAnchor).isActive = true

    // Update the layout after we just added the view on the right: 
    view.layoutSubtreeIfNeeded()

    // Starting with macOS High Sierra, animating constraint changes for the newly inserted view
    // only works if scheduled on the next runloop:
    //DispatchQueue.main.async {


         // Update the constraints to pin the view to the left:

        self.view.removeConstraint(self.activeSlideLeadingConstraint!)

        self.activeSlideLeadingConstraint = viewController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor)
        self.activeSlideLeadingConstraint?.constant = 0
        self.activeSlideLeadingConstraint?.isActive = true

        NSAnimationContext.runAnimationGroup( { context in

            self.isAnimating = true

            context.duration = self.slidingAnimationDuration
            context.allowsImplicitAnimation = true


            self.view.layoutSubtreeIfNeeded()

        }, completionHandler: {

            viewToTheLeft.removeFromSuperview()

            self.clearUndoHistory()

            self.updateFirstResponder()

            self.isAnimating = false
        })
    //}
}

1 ответ

Включите поддержку Core Animation для корневого представления, которое вы пытаетесь анимировать. Это можно сделать в Интерфейсном Разработчике или программно:

override func viewDidLoad()
{
    super.viewDidLoad()
    view.wantsLayer = true
}
Другие вопросы по тегам