Как представить контроллер представления слева направо в iOS?

При добавлении нового контроллера в стек навигации:

self.navigationController!.pushViewController(PushedViewController(), animated: true)

он появляется справа:

enter image description here

Как изменить направление анимации, чтобы оно отображалось слева?

Ответ 1

Swift 5.1: переход с разных сторон

Вот простое расширение для разных направлений. (Проверено в Swift 5)

Похоже, вы хотите использовать segueFromLeft(). Я добавил и другие примеры.

extension CATransition {

//New viewController will appear from bottom of screen.
func segueFromBottom() -> CATransition {
    self.duration = 0.375 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromTop
    return self
}
//New viewController will appear from top of screen.
func segueFromTop() -> CATransition {
    self.duration = 0.375 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromBottom
    return self
}
 //New viewController will appear from left side of screen.
func segueFromLeft() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromLeft
    return self
}
//New viewController will pop from right side of screen.
func popFromRight() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.reveal
    self.subtype = CATransitionSubtype.fromRight
    return self
}
//New viewController will appear from left side of screen.
func popFromLeft() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.reveal
    self.subtype = CATransitionSubtype.fromLeft
    return self
   }
}

А вот как вы реализуете указанное расширение:

    let nav = self.navigationController //grab an instance of the current navigationController
    DispatchQueue.main.async { //make sure all UI updates are on the main thread.
        nav?.view.layer.add(CATransition().segueFromLeft(), forKey: nil)
        nav?.pushViewController(YourViewController(), animated: false)
    }

Ответ 2

let obj = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")as! ViewController

        let transition:CATransition = CATransition()
        transition.duration = 0.3
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        self.navigationController!.view.layer.add(transition, forKey: kCATransition)

        self.navigationController?.pushViewController(obj, animated: true)

Когда вы используете popToViewController, время

 transition.subtype = kCATransitionFromRight

Ответ 3

Я использовал Hero в качестве решения.

import Hero

Затем в том месте, где вы собираетесь показать новый UIViewController, включите анимацию по умолчанию:

Hero.shared.defaultAnimation = HeroDefaultAnimationType.cover(direction: .right)

Также укажите, что ваш UINavigationController будет использовать библиотеку Hero:

self.navigationController?.hero.isEnabled = true

После этого вы получите ожидаемый результат, даже если вы используете стандартную функцию pushViewController:

self.navigationController?.pushViewController(vc, animated: true)

enter image description here

Ответ 5

Хорошо, здесь вы найдете решение для вас. Добавьте файл с именем LeftToRightTransitionProxy.swift со следующим контентом

import UIKit

final class LeftToRightTransitionProxy: NSObject {

    func setup(with controller: UINavigationController) {
        controller.delegate = self
    }
}

extension LeftToRightTransitionProxy: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == .push {
            return AnimationController(direction: .forward)
        } else {
            return AnimationController(direction: .backward)
        }
    }
}

private final class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    enum Direction {
        case forward, backward
    }

    let direction: Direction

    init(direction: Direction) {
        self.direction = direction
    }

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to),
            let fromView = transitionContext.view(forKey: .from) else {
                return
        }

        let container = transitionContext.containerView
        container.addSubview(toView)

        let initialX: CGFloat
        switch direction {
        case .forward: initialX = -fromView.bounds.width
        case .backward: initialX = fromView.bounds.width
        }
        toView.frame = CGRect(origin: CGPoint(x: initialX, y: 0), size: toView.bounds.size)

        let animation: () -> Void = {
            toView.frame = CGRect(origin: .zero, size: toView.bounds.size)
        }
        let completion: (Bool) -> Void = { _ in
            let success = !transitionContext.transitionWasCancelled
            if !success {
                toView.removeFromSuperview()
            }
            transitionContext.completeTransition(success)
        }
        UIView.animate(
            withDuration: transitionDuration(using: transitionContext),
            animations: animation,
            completion: completion
        )
    }
}

И вот как вы можете это использовать:

final class ViewController: UIViewController {

    let animationProxy = LeftToRightTransitionProxy()

    override func viewDidLoad() {
        super.viewDidLoad()

        animationProxy.setup(with: navigationController!)
    }
}

Это решение обеспечивает анимацию для направления вперед и назад (push и pop). Это можно управлять navigationController(_:animationControllerFor:from:to:) методы вашего LeftToRightTransitionProxy класса (просто возвращает nil, чтобы удалить анимацию).

Если вам нужно это поведение для определенного подкласса UIViewController поместите соответствующие проверки в метод navigationController(_:animationControllerFor:from:to:):

func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    if operation == .push && toVC is DetailViewController {
        return AnimationController(direction: .forward)
    } else if operation == .pop && toVC is ViewController {
        return AnimationController(direction: .backward)
    }
    return nil
}

Ответ 6

Это может помочь вам

let nextVc  = self.storyboard?.instantiateViewController(withIdentifier: "nextVc")
    let transition = CATransition()
    transition.duration = 0.5
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromLeft
    transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    self.navigationController?.pushViewController(nextVc!, animated: false)

Ответ 7

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

Ключевым моментом, который вам нужно сделать, является настройка делегата, настраиваемого контроллера представления и настраиваемого контроллера анимации.