Интерактивный переход UIViewController. Представленное представление исчезает при отмене интерактивного закрытия. - PullRequest
0 голосов
/ 09 января 2019

У меня есть демонстрационное приложение, в котором я пытаюсь имитировать интерактивный переход почтового приложения «новое сообщение». Вот как выглядит почтовый переход:

Mail app new message transition

Обратите внимание, как вы можете перетащить вниз, чтобы отклонить, но если вы не перетаскиваете достаточно далеко, представление снова поднимается вверх, и переход отменяется. Мне удалось продублировать переход и интерактивность в моем демонстрационном приложении, но я заметил, что когда отменяется переход отклонения, представленный контроллер представления возвращается на свое место, а затем исчезает. Вот как это выглядит:

enter image description here

Мое лучшее предположение состоит в том, что контейнерное представление контекста перехода по какой-то причине удаляется, поскольку я добавил представленное представление контроллера представления. Вот код представления и отклонения внутри UIViewControllerAnimatedTransitioning объектов:

Показать переход

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    guard let fromVC = transitionContext.viewController(forKey: .from),
        let toVC = transitionContext.viewController(forKey: .to)
        else {
            return
    }

    let containerView = transitionContext.containerView
    let finalFrame = transitionContext.finalFrame(for: toVC)
    let duration = transitionDuration(using: transitionContext)
    let topSafeAreaSpace = fromVC.view.safeAreaInsets.top // using fromVC safe area since it's on screen and has correct insets
    let topGap: CGFloat = topSafeAreaSpace + 20

    containerView.addSubview(toVC.view)

    toVC.view.frame = CGRect(x: 0,
                             y: containerView.frame.height,
                             width: toVC.view.frame.width,
                             height: toVC.view.frame.height - 30)

    UIView.animate(withDuration: duration, animations: {
        toVC.view.frame = CGRect(x: finalFrame.minX,
                                 y: finalFrame.minY + topGap,
                                 width: finalFrame.width,
                                 height: finalFrame.height - topGap)

        let sideGap: CGFloat = 20
        fromVC.view.frame = CGRect(x: sideGap,
                                   y: topSafeAreaSpace,
                                   width: fromVC.view.frame.width - 2 * sideGap,
                                   height: fromVC.view.frame.height - 2 * topSafeAreaSpace)
        fromVC.view.layer.cornerRadius = 10
        fromVC.view.layoutIfNeeded()
    }) { _ in
        transitionContext.completeTransition(true)
    }
}

Отключить переход

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    guard let fromVC = transitionContext.viewController(forKey: .from),
        let toVC = transitionContext.viewController(forKey: .to)
        else {
            return
    }

    let finalFrame = transitionContext.finalFrame(for: toVC)
    let duration = transitionDuration(using: transitionContext)

    UIView.animate(withDuration: duration, animations: {
        toVC.view.frame = finalFrame
        fromVC.view.frame = CGRect(x: fromVC.view.frame.minX,
                                   y: finalFrame.height,
                                   width: fromVC.view.frame.width,
                                   height: fromVC.view.frame.height)

        toVC.view.layer.cornerRadius = 0

        toVC.view.layoutIfNeeded()
    }) { _ in
        transitionContext.completeTransition(true)
    }
}

А вот код в UIPercentDrivenInteractiveTransition объекте:

func handleGesture(_ gesture: UIPanGestureRecognizer) {
    #warning("need to use superview?")
    let translation = gesture.translation(in: gesture.view)
    var progress = translation.y / 400
    progress = min(1, max(0, progress)) // constraining value between 1 and 0

    switch gesture.state {
    case .began:
        interactionInProgress = true
        viewController.dismiss(animated: true, completion: nil)
    case .changed:
        shouldCompleteTransition = progress > 0.5
        update(progress)
    case .cancelled:
        interactionInProgress = false
        cancel()
    case .ended:
        interactionInProgress = false
        if shouldCompleteTransition {
            finish()
        } else {
            cancel()
        }
    default:
        break
    }
}

Любая помощь будет принята с благодарностью. Стоит отметить, что я использовал этот учебник Рэя Вендерлиха в качестве справочного материала - https://www.raywenderlich.com/322-custom-uiviewcontroller-transitions-getting-started Однако, где они использовали снимки изображения для анимации перехода, я использую представления контроллера представления.

1 Ответ

0 голосов
/ 09 января 2019

Благодаря комментарию @Dare я понял, что все, что нужно, это небольшое обновление блока завершения анимации dismiss:

// before - broken

transitionContext.completeTransition(true)

// after - WORKING!

transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
...