В разное время в своем приложении я замечал, что когда я вызываю UIView.animateWithDuration
, если у меня есть какие-либо другие запросы автоматического макета или даже что-то столь же простое, как изменение константы NSLayoutConstraint
, эти изменения также будут анимированы, даже если они НЕ находятся внутри блока анимации. Например: у меня есть UIViewController
, который сразу после вызова viewDidAppear
добавит изображение, выбранное пользователем, к UIScrollView
, чтобы его можно было изменить и отредактировать. Я работаю над добавлением небольшого демонстрационного представления с несколькими GIF-файлами, чтобы помочь пользователю при первом использовании приложения. Как только представление отобразится, оно должно добавить изображение (сначала я установил его так, чтобы оно соответствовало их экрану) в scrollView, а затем анимировать demonstrationView
alpha от нуля до 1.0. Проблема, с которой я сталкиваюсь, заключается в том, что хотя моя функция добавления и изменения размера изображения assignImageChosen
вызывается перед animateWithDuration
и находится за пределами блока анимации, изменения ограничений размера также анимируются.
override func viewDidAppear(animated: Bool) {
if let image = startImage {
self.assignImageChosen(image)
currentlyEditing = true
}
if preLoadGame {
UIView.animateWithDuration(1.0, delay: 0.5, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.demonstrationView.alpha = 1.0
self.view.layoutIfNeeded()
}, completion: nil)
}
}
Вот функция assignImageChosen
:
func assignImageChosen(image: UIImage) {
var ratio:CGFloat!
let screen:CGFloat = max(self.scrollView.frame.height, self.scrollView.frame.width)
var maxImage:CGFloat!
if UIDevice.currentDevice().orientation.isPortrait {
if image.size.height >= image.size.width {
maxImage = max(image.size.height, image.size.width)
}
else {
maxImage = min(image.size.height, image.size.width)
}
}
else {
if image.size.width >= image.size.height {
maxImage = max(image.size.height, image.size.width)
}
else {
maxImage = min(image.size.height, image.size.width)
}
}
if maxImage > screen {
ratio = screen/maxImage
}
else {
ratio = 1.0
}
self.imageView.image = image
self.imageHeight.constant = image.size.height * ratio
self.scrollView.contentSize.height = image.size.height * ratio
self.imageWidth.constant = image.size.width * ratio
self.scrollView.contentSize.width = image.size.width * ratio
}
Переменные imageHeight
и imageWidth
являются переменными NSLayoutConstraint
, а imageView
— это переменные UIImageView
, для которых они установлены. Поэтому, как только я изменяю изображение, я изменяю ограничения, чтобы изображение внутри UIScrollView
подходило для экрана. Проблема в том, что когда я делаю это таким образом, даже если изменения вызываются вне блока анимации, эти изменения все равно анимируются.
Вот пример GIF того, что я пытаюсь (плохо) передать словами:
Я нашел способ обойти эту проблему, но это похоже на полный взлом. Я вручную программирую систему для задержки выполнения анимации с помощью команды dispatch_after
следующим образом:
override func viewDidAppear(animated: Bool) {
if let image = startImage {
self.assignImageChosen(image)
currentlyEditing = true
}
if preLoadGame {
let delay = 0.5 * Double(NSEC_PER_SEC)
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(popTime, dispatch_get_main_queue(), {
UIView.animateWithDuration(1.0, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.demonstrationView.alpha = 1.0
self.view.layoutIfNeeded()
}, completion: nil)
})
}
}
Поэтому вместо того, чтобы использовать переменную delay
внутри функции animateWithDuration
, я задержу выполнение функции. Это работает, но я думаю, что должен быть лучший способ сделать это! Почему эти изменения макета анимируются, если они не находятся внутри блока анимации? Как я могу обойти это надлежащим и эффективным образом?
Вот как это выглядит с моим хаком, и как я представляю, что должно выглядеть без него:
Я ценю любую помощь с этой неприятной проблемой!