我正在尝试创建自定义标注气泡。 我有一个动画 block 设置气泡 UIView 的比例变换:
self.view.transform = CGAffineTransformMakeScale(0, 0); // (1)
self.view.transform = CGAffineTransformIdentity; // (2)
我要么像 (1) 中那样以比例 (0, 0) 开始气泡 View ,然后在动画 block 内像 (2) 中那样对 Identity 进行动画处理,或者相反,从 (2) 到 (1)。
如果我的动画 block 中没有 [self.view layoutIfNeeded];
,从 (1) 到 (2) 可以正常工作,如下所示:
但是当没有 [self.view layoutIfNeeded];
从 (2) 返回到 (1) 时, subview 在动画完成之前跳到左边:
现在,如果我确实添加了 [self.view layoutIfNeeded];
, subview 会随着气泡 View 而动画化,但会有一些延迟:
从 (1) 到 (2):
或者从(2)到(1):
我已经尝试用中心约束替换所有顶部和前导 subview 的约束,如 How do I adjust the anchor point of a CALayer, when Auto Layout is being used?并且还尝试了层变换解决方案(但是这个解决方案打破了布局约束,说它不能满足所有约束)。
关于如何解决我的动画问题有什么想法吗?
提前致谢。
更新: 我正在用我调用的实际方法更新问题
- (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);
}
}
}
最佳答案
这可能会有所帮助。根据 Apple 文档 -layoutIfNeeded 强制提前布局
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
所以,你可以试试setNeedsLayout。这应该满足您提到的第一种情况。
关于ios - 在 UIView 动画 block 中调用 layoutIfNeeded 会导致 subview 更早移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22601541/