Анимация ограничений автоматического макета с помощью NSView.layoutSubtreeIfNeeded() не работает на MacOS High Sierra
У меня есть базовое приложение Mac с анимацией представления, выполненной с помощью Auto Layout:
- Я добавляю новый вид справа от текущего вида
- Я обновляю ограничения так, чтобы новый вид заканчивал тем, что заполнил окно
→ Анимация будет выглядеть так, как будто вид скользит справа.
Рекомендуемый способ анимации изменений Auto Layout:
- Обновите ограничения
- использование
NSAnimationContext.runAnimationGroup()
- Задавать
allowsImplicitAnimation
вtrue
внутри блока анимации - Вызов
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
}