在CABasicAnimation之后,NSView不响应鼠标事件

时间:2012-11-30 19:12:58

标签: cocoa animation core-animation mouseevent

我有一个pageLeftpageRight动画可以动画显示2个视图的位置和alpha值,总共可以同时显示4个CABasicAnimation

  1. 将下一页移至视图
  2. 将当前页面移出视图
  3. 淡入下一页
  4. 淡出当前页面
  5. 一切都适用于动画和设置。这个问题是关于页面动画后的鼠标事件。我发现在动画运行后,nextView 不会接收mouseDown:个事件。如果由于shouldNotAnimate块在下面运行而未运行动画,则nextView 接收mouseDown:个事件。

    这意味着有关我设置CABasicAnimationCATransaction的方式的原因导致此问题。我很难过它会是什么。有什么想法吗?


    动画代码:

    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];
        }];
    

2 个答案:

答案 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版本更新后问题就消失了,所以很可能是边缘情况引起的错误。我提出了一个关于这个问题的错误,这可能有助于提高对意外行为的认识。