我有一个pageLeft
和pageRight
动画可以动画显示2个视图的位置和alpha值,总共可以同时显示4个CABasicAnimation
:
一切都适用于动画和设置。这个问题是关于页面动画后的鼠标事件。我发现在动画运行后,nextView
不会接收mouseDown:
个事件。如果由于shouldNotAnimate
块在下面运行而未运行动画,则nextView
会接收mouseDown:
个事件。
这意味着有关我设置CABasicAnimation
和CATransaction
的方式的原因导致此问题。我很难过它会是什么。有什么想法吗?
动画代码:
BOOL forward = currentIndex < index;
if (shouldNotAnimate) {
// handles swapping pages faster than the animation duration
[self.sourceViewContainer setSubviews:[NSArray array]];
[nextView.layer removeAllAnimations];
[nextView setFrame:self.sourceViewContainer.bounds];
[nextView.layer setPosition:self.sourceViewContainer.bounds.origin];
[nextView.layer setOpacity:1.0];
[self.sourceViewContainer addSubview:nextView];
[currentView removeFromSuperview];
[currentView.layer removeAllAnimations];
[currentView setFrame:self.sourceViewContainer.bounds];
[currentView.layer setPosition:self.sourceViewContainer.bounds.origin];
[currentView.layer setOpacity:1.0];
self.animationsRunning = NO;
} else {
self.animationsRunning = YES;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
self.animationsRunning = NO;
}];
// Setup incoming push animation
[nextView setFrame:CGRectMake(self.sourceViewContainer.bounds.size.width * (forward ? 1 : -1), 0, self.sourceViewContainer.bounds.size.width, self.sourceViewContainer.bounds.size.width)];
[self.sourceViewContainer addSubview:nextView];
CABasicAnimation *incomingAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
incomingAnimation.fromValue = [NSValue valueWithPoint:nextView.frame.origin];
incomingAnimation.toValue = [NSValue valueWithPoint:self.sourceViewContainer.bounds.origin];
incomingAnimation.duration = PANEL_PAGE_SWIPE_ANIMATION_DURATION;
incomingAnimation.removedOnCompletion = NO;
incomingAnimation.fillMode = kCAFillModeForwards;
incomingAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
incomingAnimation.completion = ^(BOOL finished) {
[nextView.layer setPosition:self.sourceViewContainer.bounds.origin];
[nextView.layer removeAnimationForKey:@"incoming"];
};
[nextView.layer addAnimation:incomingAnimation forKey:@"incoming"];
// Setup outgoing push animation
CGRect offscreen = CGRectMake(self.sourceViewContainer.bounds.size.width * (forward ? -1 : 1), 0, self.sourceViewContainer.bounds.size.width, self.sourceViewContainer.bounds.size.height);
CABasicAnimation *outgoingAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
outgoingAnimation.fromValue = [NSValue valueWithPoint:self.sourceViewContainer.bounds.origin];
outgoingAnimation.toValue = [NSValue valueWithPoint:offscreen.origin];
outgoingAnimation.duration = PANEL_PAGE_SWIPE_ANIMATION_DURATION;
outgoingAnimation.removedOnCompletion = NO;
outgoingAnimation.fillMode = kCAFillModeForwards;
outgoingAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
outgoingAnimation.completion = ^(BOOL finished) {
[currentView removeFromSuperview];
[currentView.layer setPosition:self.sourceViewContainer.bounds.origin];
[currentView.layer removeAnimationForKey:@"outgoing"];
};
[currentView.layer addAnimation:outgoingAnimation forKey:@"outgoing"];
// Setup incoming alpha animation
CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeInAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
fadeInAnimation.toValue = [NSNumber numberWithFloat:1.0f];
fadeInAnimation.duration = PANEL_PAGE_SWIPE_ANIMATION_DURATION;
fadeInAnimation.removedOnCompletion = NO;
fadeInAnimation.fillMode = kCAFillModeForwards;
fadeInAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
fadeInAnimation.completion = ^(BOOL finished) {
[nextView.layer setOpacity:1.0f];
[nextView.layer removeAnimationForKey:@"fadeIn"];
};
[nextView.layer addAnimation:fadeInAnimation forKey:@"fadeIn"];
// Setup outgoing alpha animation
CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeOutAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
fadeOutAnimation.toValue = [NSNumber numberWithFloat:0.0f];
fadeOutAnimation.duration = PANEL_PAGE_SWIPE_ANIMATION_DURATION;
fadeOutAnimation.removedOnCompletion = NO;
fadeOutAnimation.fillMode = kCAFillModeForwards;
fadeOutAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
fadeOutAnimation.completion = ^(BOOL finished) {
[currentView removeFromSuperview];
[currentView.layer setOpacity:1.0f];
[currentView.layer removeAnimationForKey:@"fadeOut"];
};
[currentView.layer addAnimation:fadeOutAnimation forKey:@"fadeOut"];
[CATransaction commit];
} // Run animations
解决方案
我必须在完成块中显式设置视图框,即使我在动画调用之前立即执行了此操作。
[CATransaction begin];
[CATransaction setCompletionBlock:^{
self.animationsRunning = NO;
[nextView setFrame:self.sourceViewContainer.bounds];
}];
答案 0 :(得分:1)
我想我知道发生了什么事。
CAAnimation对象实际上并不会更改它们动画的基础属性。相反,它将属性应用于表示层,而表示层是绘制而不是常规图层。使用removedOnCompletion = false创建动画时,表示层在动画完成后保持活动状态,但基础属性仍未更改。此外,移动视图的图层不会移动视图本身,因此它不会响应用户在新位置的交互。
我建议使用UIView块动画(UIView animateWithDuration:completion:和它的亲戚)而不是使用CAAnimation对象来移动视图。这些方法实际上将视图移动到它的新位置,以便在动画完成后它响应最终位置的用户交互。
你可以在一个动画块中进行移动和alpha更改。
答案 1 :(得分:0)
我曾经遇到过UIMapView的问题,因为调用地图视图后动画后没有响应。动画结束后,以某种方式将userInteractionEnable设置为FALSE。
如果确实是这种情况,您可以做的是断言userInteractionEnable的值为TRUE。
assert(view.userInteractionEnable != FALSE); // ensure user interaction is enabled
您可能会发现当您运行应用程序时,它会断言此断言。如果是这样,您只需将其设置为TRUE,您的应用就会按预期工作。
至于我的UIMapView问题,iOS版本更新后问题就消失了,所以很可能是边缘情况引起的错误。我提出了一个关于这个问题的错误,这可能有助于提高对意外行为的认识。