13

私は新しい iOS 7 カスタム トランジション API に手を出して、見つけたすべてのチュートリアル/ドキュメントを調べましたが、特定のシナリオでこのようなものを理解できないようです。

したがって、本質的に私が実装しようとしているのは、上にスワイプして VC に移行するビューの UIPanGestureRecognizer です。VC のビューは下から上にスライドし、現在のビューは指を上にドラッグすると上にスライドします。

インタラクション トランジションなしでこれを達成するのに問題はありませんが、インタラクション (パン ジェスチャ) を実装すると、トランジションを完了できないようです。

アニメーターコントローラーを販売するために必要な UIViewControllerTransitionDelegate に準拠する VC からの関連コードを次に示します。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"Swipe"]) {
        NSLog(@"PREPARE FOR SEGUE METHOD CALLED");

        UIViewController *toVC = segue.destinationViewController;
        [interactionController wireToViewController:toVC];
        toVC.transitioningDelegate = self;
        toVC.modalPresentationStyle = UIModalPresentationCustom;
      }
}

#pragma mark UIViewControllerTransition Delegate Methods

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:  (UIViewController *)presented                                                                   presentingController:  (UIViewController *)presenting sourceController:(UIViewController *)source {
    NSLog(@"PRESENTING ANIMATION CONTROLLER CALLED");

    SwipeDownPresentationAnimationController *transitionController = [SwipeDownPresentationAnimationController new];
    return transitionController;
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    NSLog(@"DISMISS ANIMATION CONTROLLER CALLED");

    DismissAnimatorViewController *transitionController = [DismissAnimatorViewController new];
    return transitionController;
}

- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator {
    NSLog(@"Interaction controller for dimiss method caled");

    return interactionController.interactionInProgress ? interactionController:nil;
}

注: インタラクション スワイプは、VC の却下のみを目的としているため、interactionControllerForDismissal メソッドに含まれています。

これは、ボタンをタップして閉じると正常に動作する、解雇のアニメーターのコードです。

#import "DismissAnimatorViewController.h"

@implementation DismissAnimatorViewController

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
    return 1.0;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    NSTimeInterval duration = [self transitionDuration:transitionContext];

    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    CGRect initialFrameFromVC = [transitionContext initialFrameForViewController:fromVC];

    UIView *containerView = [transitionContext containerView];

    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    NSLog(@"The screen bounds is :%@", NSStringFromCGRect(screenBounds));
    toVC.view.frame = CGRectOffset(initialFrameFromVC, 0, screenBounds.size.height);
    toVC.view.alpha = 0.2;

    CGRect pushedPresentingFrame = CGRectOffset(initialFrameFromVC, 0, -screenBounds.size.height);

    [containerView addSubview:toVC.view];

    [UIView animateWithDuration:duration
                          delay:0
         usingSpringWithDamping:0.6
          initialSpringVelocity:0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{
                         fromVC.view.frame = pushedPresentingFrame;
                         fromVC.view.alpha = 0.2;
                         toVC.view.frame = initialFrameFromVC;
                         toVC.view.alpha = 1.0;
                     } completion:^(BOOL finished) {
                         [transitionContext completeTransition:YES];
                     }];
}

@end

インタラクション コントローラーとして機能する UIPercentDrivenInteractiveTransition サブクラスのコードは次のとおりです。

#import "SwipeInteractionController.h"

@implementation SwipeInteractionController {
    BOOL _shouldCompleteTransition;
    UIViewController *_viewController;
}

- (void)wireToViewController:(UIViewController *)viewController {
    _viewController = viewController;
    [self prepareGestureRecognizerInView:_viewController.view];
}

- (void)prepareGestureRecognizerInView:(UIView*)view {
    UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    gesture.minimumNumberOfTouches = 1.0;

    [view addGestureRecognizer:gesture];
}

- (CGFloat)completionSpeed {
    return 1 - self.percentComplete;
    NSLog(@"PERCENT COMPLETE:%f",self.percentComplete);
}

- (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer {
//    CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];
    CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];

    switch (gestureRecognizer.state) {
        case UIGestureRecognizerStateBegan:
            // 1. Start an interactive transition!
            self.interactionInProgress = YES;
            [_viewController dismissViewControllerAnimated:YES completion:nil];
            break;
        case UIGestureRecognizerStateChanged: {
            // 2. compute the current position
            CGFloat fraction = fabsf(translation.y / 568);
            NSLog(@"Fraction is %f",fraction);
            fraction = fminf(fraction, 1.0);
            fraction = fmaxf(fraction, 0.0);
            // 3. should we complete?
            _shouldCompleteTransition = (fraction > 0.23);
            // 4. update the animation controller
            [self updateInteractiveTransition:fraction];
            NSLog(@"Percent complete:%f",self.percentComplete);
            break;
        }
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled: {
            // 5. finish or cancel
            NSLog(@"UI GESTURE RECOGNIZER STATE CANCELED");
            self.interactionInProgress = NO;
            if (!_shouldCompleteTransition || gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
                [self cancelInteractiveTransition];
                NSLog(@"Interactive Transition is cancled.");
                }
            else {
                NSLog(@"Interactive Transition is FINISHED");
                [self finishInteractiveTransition];
            }
            break;
        }
        default:
            NSLog(@"Default is being called");
            break;
    }
}

@end

繰り返しになりますが、ここでコードを実行し、遷移を意図的にキャンセルするために完全にスワイプしないと、フラッシュが表示され、スワイプ先のビュー コントローラーが表示されます。これは、移行が完了したかキャンセルされたかに関係なく発生します。

ただし、ボタンを使用して閉じると、アニメーター ビュー コントローラーで指定されたトランジションが取得されます。

4

2 に答える 2

22

ここでいくつかの問題を確認できますが、これらで問題が解決するかどうかはわかりません。

まず、アニメーション コントローラーの UIView アニメーション完了ブロックには次のものがあります。

[transitionContext completeTransition:YES];

次のように、対話コントローラーの結果に基づいて完了を返す必要があります。

[transitionContext completeTransition:![transitionContext transitionWasCancelled]]

UIPercentDrivenInteractiveTransitionまた、遷移が 100% 完了したことを に伝えると、アニメーション コントローラーの完了ブロックが呼び出されないことがわかりました。回避策として、~99.9% に制限します。

https://github.com/ColinEberhardt/VCTransitionsLibrary/issues/4

ここでは、役に立つと思われるインタラクションおよびアニメーション コントローラーの例をいくつか作成しました。

https://github.com/ColinEberhardt/VCTransitionsLibrary

于 2013-10-02T09:03:49.067 に答える
2

私はこれと同じ問題を抱えていました。上記の修正やその他の修正を試みましたが、何も機能しませんでした。それから、すべてを修正したhttps://github.com/MrAlek/AWPercentDrivenInteractiveTransitionに出くわしました。

UIPercentDrivenInteractiveTransitionプロジェクトに追加したら、 に置き換えるだけAWPercentDrivenInteractiveTransitionです。

また、インタラクティブなトランジションを開始する前にアニメーターを設定する必要があります。私の場合、 と に同じクラスを使用するUIViewControllerAnimatedTransitioningのでUIViewControllerInteractiveTransitioning、 でそれを行いましたinit():

init() {
    super.init()
    self.animator = self
}
于 2015-04-23T21:48:53.587 に答える