1

2 つのビューの位置とアルファをアニメーション化するアニメーションがあり、合計 4 つの同時 spageLeftが作成されます。pageRightCABasicAnimation

  1. 次のページをビューに移動
  2. 現在のページをビューの外に移動します
  3. 次のページにフェードイン
  4. 現在のページをフェードアウト

すべてがアニメーションとセットアップでうまく機能します。この質問は、ページ アニメーション後のマウス イベントに関するものです。アニメーションの実行後、 がイベントを受信nextView しないことがわかりました。代わりにブロックが下でmouseDown:実行されるためにアニメーションが実行されない場合、 はイベントを受け取ります。shouldNotAnimatenextView mouseDown:

これは、私がCABasicAnimations をセットアップした方法と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];
    }];
4

2 に答える 2

1

私は何が起こっているのか知っていると思います。

CAAnimation オブジェクトは、アニメーション化する基になるプロパティを実際には変更しません。代わりに、通常のレイヤーの代わりに描画されるプレゼンテーション レイヤーにプロパティを適用します。removedOnCompletion=false でアニメーションを作成すると、アニメーションの完了後もプレゼンテーション レイヤーはアクティブなままになりますが、基になるプロパティは変更されません。さらに、ビューのレイヤーを移動してもビュー自体は移動しないため、新しい場所でのユーザーの操作には応答しません。

CAAnimation オブジェクトを使用する代わりに、UIView ブロック アニメーション (UIView animateWithDuration:completion: とその親戚) を使用してビューを移動することをお勧めします。これらのメソッドは実際にビューを新しい位置に移動するため、アニメーションが完了すると、最終的な位置でユーザーの操作に応答します。

移動とアルファの変更をすべて 1 つのアニメーション ブロックで行うことができます。

于 2012-12-01T01:43:19.153 に答える
0

マップ ビューへの呼び出しが原因で、アニメーション後に UIMapView が応答しないという iOS の問題がありました。アニメーションが終了した後、どういうわけか userInteractionEnable が FALSE に設定されました。

そうであるかどうかをテストするためにできることは、userInteractionEnable の値が TRUE であることをアサートすることです。

assert(view.userInteractionEnable != FALSE); // ensure user interaction is enabled

アプリを実行すると、このアサーションで中断することがあります。そうであれば、TRUE に設定するだけで、アプリは期待どおりに動作します。

私のUIMapViewの問題は、iOSのバージョンアップで問題がなくなったので、エッジケースによるバグである可能性が高いです。予期しない動作についての認識を高めるのに役立った可能性がある問題についてバグを報告しました。

于 2012-11-30T19:51:53.690 に答える