layoutSubviews во время анимации? - PullRequest
13 голосов
/ 12 сентября 2010

У меня есть UIView с кучей подпредставлений, все расположены с использованием layoutSubviews. При изменении размера view все относительные позиции изменяются. Я хотел бы, чтобы эти пересчеты происходили во время анимированного изменения размера (с использованием + [UIView beginAnimations:] вызовов) Кажется, этого не происходит. Есть идеи?

Ответы [ 4 ]

24 голосов
/ 12 сентября 2010

Предположение: необходимо выполнить несколько шагов анимации (то есть положение не изменяется линейно с размером кадра).

Это невозможно с одной «стандартной» анимацией UIView. Зачем? Рамка / границы устанавливаются только один раз.

Базовая анимация имеет три "дерева слоев":

  • Дерево моделей - это то, где ваше приложение думает о вещах.
  • Дерево презентаций - это примерно то, что отображается на экране.
  • Дерево визуализации - это примерно то, что Core Animation создает.

UIView - это (несколько тонкая) оболочка вокруг слоя модели. Во время анимации UIView Core Animation обновляет дерево представления / рендеринга & mdash; дерево модели представляет конечную точку анимации. В результате ваш код может (по большей части) обрабатывать анимацию как мгновенную & mdash; перемещение вида из А в В мгновенно перемещает его в В; Изменения как раз анимированы для пользователя.

Существуют более сложные вещи, которые вы можете сделать непосредственно с помощью CALayer / CAAnimation, но я не очень много исследовал.

Вы можете связать несколько анимаций вместе, используя - [UIView setAnimationDidStopSelector:]. (Вы также можете попробовать использовать несколько анимаций вместе с setAnimationDelay :, но я не уверен, что происходит с несколькими анимациями в одном и том же свойстве; вам может повезти с setAnimationBeginsFromCurrentState:.)

Если вы хотите действительно детальное управление, CADisplayLink (OS 3.1+) - это таймер, который срабатывает после каждого обновления экрана. Резервным вариантом (для поддержки 3.0) является использование NSTimer с частотой 30/60 Гц или около того.

14 голосов
/ 25 сентября 2014

Завершая ответ @ GrizzlyNetch, вы можете установить параметр анимации UIViewAnimationOptionLayoutSubviews, поэтому вам не нужно звонить layoutIfNeeded:

-(void)someMethod{
    double duration = ...;
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
        self.frame = ...;
    } completion:nil];
}
13 голосов
/ 05 сентября 2012

Я знаю, что это старый вопрос, но этот код работает для меня очень хорошо (подходит для вашего примера изменения фрейма).

-(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).

как тс. Хорошо объяснив «деревья слоев», вы просто заставляете слой представления отображать финальную стадию слоя модели с анимацией.

Преимущество этого метода заключается в возможности контролировать, когда изменение кадра / границ анимируется и когда оно происходит мгновенно.

Надеюсь, это кому-нибудь поможет:).

5 голосов
/ 12 сентября 2010

Проводка для полноты. Благодаря тк. для объяснения того, что именно то, что я хочу сделать, не поддерживается Core Animation.

В конце концов я нашел разумное решение. Вместо того, чтобы размещать мои подпредставления в -layoutSubviews, я делаю это в -setBounds :. Затем, когда я обертываю -setBounds: call в блоке UIView + beginAnimations:, эти позиционные вызовы также анимируются, и конечным результатом является то, что все правильно анимируется туда, где это должно быть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...