Вызов layoutIfNeeded внутри блока анимации UIView приводит к тому, что подпредставления перемещаются раньше
Я пытаюсь создать собственный пузырь выноски. У меня есть блок анимации, устанавливающий масштабное преобразование пузырька UIView:
self.view.transform = CGAffineTransformMakeScale(0, 0); // (1)
self.view.transform = CGAffineTransformIdentity; // (2)
Я либо запускаю пузырьковое представление с масштабом (0, 0), как в (1), и анимирую в Identity, как в (2) внутри блока анимации, или наоборот, переходя от (2) к (1).
Если у меня нет [self.view layoutIfNeeded];
в моем анимационном блоке переход от (1) к (2) работает нормально, как в:
Но при переходе от (2) к (1) без [self.view layoutIfNeeded];
, подпредставления переходят влево до завершения анимации:
Теперь, если я добавлю [self.view layoutIfNeeded];
подпредставления анимируются в виде пузыря, но с некоторой задержкой:
Либо переходя от (1) к (2):
Или из (2) в (1):
Я уже пытался заменить все верхние и ведущие ограничения подпредставления центральными ограничениями, как в разделе Как настроить точку привязки CALayer, когда используется Auto Layout? и также попробовал решение преобразования слоя (но это нарушает ограничения макета, говоря, что это не может удовлетворить все ограничения).
Есть идеи, как решить мою проблему с анимацией?
Заранее спасибо.
ОБНОВЛЕНИЕ: я обновляю вопрос фактическим методом, который я вызываю
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
а также
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
представить и отклонить мой пользовательский пузырь выноски (на данный момент забудьте о расширенном состоянии).
- (void)setCalloutState:(CalloutState)calloutState
animated:(BOOL)animated
annotationView:(MKAnnotationView *)annotationView
completion:(void (^)(BOOL finished))completion
{
if (self.view.superview == annotationView || !annotationView) {
} else {
// [self.view.layer removeAllAnimations];
[self.view removeFromSuperview];
self.view.transform = CGAffineTransformIdentity;
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
self.view.transform = CGAffineTransformMakeScale(0, 0);
self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
[annotationView addSubview:self.view];
}
void (^animationBlock)(void) = ^{
self.view.transform = CGAffineTransformIdentity;
switch (calloutState) {
case CalloutStateHidden:
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
self.view.transform = CGAffineTransformMakeScale(0, 0);
break;
case CalloutStateNormal:
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
break;
case CalloutStateExpanded:
self.view.bounds = CGRectMake(0, 0, expandedViewWidth, expandedViewHeight);
break;
default:
break;
}
self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
[self.view layoutIfNeeded];
};
if (animated) {
// TODO: figure out why the first animateWithDuration is needed in this nested thing
[UIView animateWithDuration:0
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:NULL
completion:^(BOOL finished) {
[UIView animateWithDuration:1.3
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:animationBlock
completion:^(BOOL finished) {
if (finished) {
self.calloutState = calloutState;
// TODO: figure out how to end UIView animation instantly so we don't need the second condition at the if
// having a concurrency problem here
if (calloutState == CalloutStateHidden && self.view.superview == annotationView) {
[self.view removeFromSuperview];
}
self.editingEnabled = calloutState == CalloutStateExpanded;
}
if (completion) {
completion(finished);
}
}];
}];
// ---------------------------------------------------------------------------------
} else {
animationBlock();
self.calloutState = calloutState;
if (calloutState == CalloutStateHidden) {
[self.view removeFromSuperview];
}
self.editingEnabled = calloutState == CalloutStateExpanded;
if (completion) {
completion(YES);
}
}
}
1 ответ
Это может помочь. В соответствии с документацией Apple -layoutIfNeeded заставляет макет рано
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
Итак, вы можете попробовать setNeedsLayout. Это должно удовлетворить 1-й случай, который вы упомянули.