Подтвердить что ты не робот

Как завершить интерактивный переход UIViewController?

Я занимался новым API перехода на основе iOS 7 и просматривал все обучающие материалы/документацию, которые мог найти, но я не могу представить, как это отразится на моем конкретном сценарии.

Итак, по сути, я пытаюсь реализовать это UIPanGestureRecognizer в представлении, где я бы прокрутил вверх и перешел на VC, чей вид будет скользить снизу, пока текущее представление будет скользить вверх, когда я вытащу свой палец выше.

У меня нет проблем с выполнением этого без перехода взаимодействия, но как только я реализую взаимодействие (жест панорамы), я не могу завершить переход.

Вот соответствующий код из VC, который соответствует UIViewControllerTransitionDelegate, который необходим для доставки контроллеров аниматора:

- (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, поэтому в методе взаимодействияControllerForDismissal

Вот код для аниматора увольнения, который отлично работает, когда я нажимаю кнопку, чтобы отменить его:

#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

Еще раз, когда я запускаю код сейчас, и я не промахиваю полностью, чтобы целенаправленно отменить переход, я просто получаю флеш-память, и мне представляется контроллер вида, на который я хочу провести. Это происходит независимо от того, завершен или отменен переход.

Однако, когда я увольняюсь с помощью кнопки, я получаю переход, указанный в моем контроллере представления аниматора.

4b9b3361

Ответ 1

Я вижу пару проблем здесь, хотя я не могу быть уверен, что они исправят вашу проблему!

Во-первых, ваш блок завершения анимации аниматора UIView имеет следующее:

[transitionContext completeTransition:YES];

В то время как он должен возвращать завершение на основе результата контроллера взаимодействия следующим образом:

[transitionContext completeTransition:![transitionContext transitionWasCancelled]]

Кроме того, я обнаружил, что если вы сообщите UIPercentDrivenInteractiveTransition, что переход на 100% завершен, он не вызывает блок завершения контроллера анимации. В качестве обходного пути я ограничиваю его до ~ 99,9%

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

Я создал несколько примеров контроллеров взаимодействия и анимации здесь, которые могут оказаться полезными:

https://github.com/ColinEberhardt/VCTransitionsLibrary

Ответ 2

У меня была такая же проблема. Я пробовал исправления выше и другие, но ничего не получилось. Затем я наткнулся на https://github.com/MrAlek/AWPercentDrivenInteractiveTransition, который исправил все.

Как только вы добавите его в свой проект, просто замените UIPercentDrivenInteractiveTransition на AWPercentDrivenInteractiveTransition.

Кроме того, перед началом интерактивного перехода необходимо установить аниматор. В моем случае я использую тот же класс для UIViewControllerAnimatedTransitioning и UIViewControllerInteractiveTransitioning, поэтому я просто сделал это в init():

init() {
    super.init()
    self.animator = self
}