LayoutSubviews во время анимации?
У меня есть UIView
с кучей subviews, все позиционируются с помощью layoutSubviews
. Когда размер view
изменяется, относительные позиции все изменяются. Я бы хотел, чтобы эти повторные вычисления выполнялись во время анимированного изменения размера (с использованием вызовов + [UIView beginAnimations:]
). Кажется, это не происходит. Любые идеи?
Ответы
Ответ 1
Предположение: вы хотите иметь несколько шагов анимации (т.е. положение не изменяется линейно с размером кадра).
Это невозможно с помощью одной "стандартной" анимации UIView. Зачем? Рамка/граница устанавливается только один раз.
Core Animation имеет три "дерева слоев":
- Дерево моделей - это то, о чем ваше приложение думает.
- Дерево презентации примерно соответствует отображаемому на экране.
- Дерево рендеринга примерно соответствует компоновке Core Animation.
UIView - (несколько тонкая) обертка вокруг слоя модели. Во время анимации UIView Core Animation обновляет дерево презентаций/рендеринга — дерево модели представляет конечную точку анимации. Результат заключается в том, что ваш код может (по большей части) обрабатывать анимацию как мгновенный — перемещение вида от A до B мгновенно перемещает его в B; изменение просто происходит для анимированного пользователя.
С CALayer/CAAnimation можно заниматься более сложными вещами, но я этого недостаточно изучил.
Вы можете связать несколько анимаций вместе, используя - [UIView setAnimationDidStopSelector:]. (Вы также можете попробовать использовать несколько анимаций вместе с setAnimationDelay:, но я не уверен, что происходит с несколькими анимациями в одном и том же свойстве: вам может повезло с setAnimationBeginsFromCurrentState:.)
Если вам нужен действительно тонкий контроль, CADisplayLink (OS 3.1+) - это таймер, который запускается после каждого обновления экрана. Резервным вариантом (для поддержки 3.0) является использование NSTimer при 30/60 Гц или около того.
Ответ 2
Я знаю, что это старый вопрос, но этот код работает для меня очень хорошо (подходит для вашего примера смены фрейма).
-(void)layoutSubviews{
[super layoutSubviews];
// layout your subviews here, or whatever
}
-(void)someMethod{
double duration=...;
[UIView animateWithDuration:duration animations:^{
self.frame = ...;
[self layoutIfNeeded];
}];
}
Конечно, этот метод можно вызвать из другого объекта. "Трюк" - это вызов layoutIfNeeded (или layoutSubviews напрямую - то же самое, если вы меняете фрейм, который вызывается setNeedsLayout).
Как tc. приятно объяснили "деревья слоев", вы просто заставляете слой презентации отображать заключительный этап слоя модели с анимацией.
Преимущество этого метода заключается в возможности управления, когда анимация кадра/границ анимируется и когда она мгновенно.
Надеюсь, это поможет кому-то:).
Ответ 3
Завершая @GrizzlyNetch anwer, вы можете установить опцию анимации UIViewAnimationOptionLayoutSubviews
, поэтому вам не нужно вызывать layoutIfNeeded
:
-(void)someMethod{
double duration = ...;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
self.frame = ...;
} completion:nil];
}
Ответ 4
Публикация для полноты. Благодаря tc. для объяснения того, что я хочу сделать, точно, не поддерживается Core Animation.
В конце концов я придумал разумное решение. Вместо этого планируйте мои подпрограммы в -layoutSubviews, я делаю это в -setBounds:. Затем, когда я обертываю -setBounds: вызов в UIView + beginAnimations: block, эти позиционирующие вызовы также анимируются, и конечным результатом является все, что правильно оживляет, где оно должно быть богом.