Swiftを使用してiOSでViewControllerを右から左に表示する方法


82

presentViewControllerを使用して新しい画面を表示しています

let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)

これにより、新しい画面が下から上に表示されますが、を使用せずに右から左に表示したいと思いUINavigationControllerます。

ストーリーボードの代わりにXibを使用していますが、どうすればよいですか?


要するに、完全な答え:stackoverflow.com/a/48081504/294884
Fattie

回答:


158

それがあるかどうかは関係ありませんxibstoryboard、あなたが使用していること。通常、ビューコントローラをプレゼンターのにプッシュすると、右から左への遷移が使用されますUINavigiationController

更新

タイミング機能を追加 kCAMediaTimingFunctionEaseInEaseOut

サンプルプロジェクトスウィフト4のGitHubに追加実装


Swift 3&4.2

let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
present(dashboardWorkout, animated: false, completion: nil)


ObjC

CATransition *transition = [[CATransition alloc] init];
transition.duration = 0.5;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:dashboardWorkout animated:false completion:nil];


Swift 2.x

let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
view.window!.layer.addAnimation(transition, forKey: kCATransition)
presentViewController(dashboardWorkout, animated: false, completion: nil)

このカスタム遷移の場合animatedpresentViewControllerメソッドのパラメーターは実際には重要ではないようです。trueまたはのいずれかの任意の値にすることができますfalse


2
カスタムUIStoryboardSegueのperform()メソッド内でSwift3コードを使用しようとしましたが、問題は、遷移が同じビューで実行され、2番目のビューが表示されることです。それについて何かアイデアはありますか?
devarshi 2016年

2
現在、この方法を使用すると、ソースVCがフェードアウトします。そのフェード効果を削除して、プッシュアニメーションのようにするにはどうすればよいですか?
Umair Afzal 2017

1
@UmairAfzalそれはウィンドウの色です、それを避けるためにウィンドウの色を変更する必要があります。
Abdul Rehman 2017年

Swift 3のUIModalPresentationStyle.overCurrentContextでこの遷移を効果的に使用する方法
Mamta

3
「アニメーション」を「真」に設定すると、わずかに上向きのアニメーションも表示されます。「false」に設定することをお勧めします
Rebeloper 2018年

66

提示/却下の完全なコード、Swift 3

extension UIViewController {

    func presentDetail(_ viewControllerToPresent: UIViewController) {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromRight
        self.view.window!.layer.add(transition, forKey: kCATransition)

        present(viewControllerToPresent, animated: false)
    }

    func dismissDetail() {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        self.view.window!.layer.add(transition, forKey: kCATransition)

        dismiss(animated: false)
    }
}

1
具体的にお願いします。もっと説明してください !
Emm 2017年

2
却下機能もあるのであなたの答えに賛成
Rebeloper 2018年

そこに最高の1つ!👌–
シャム

42

すべての答えを読んでください、そして正しい解決策を見ることができません。そのための正しい方法は、提示されたVCデリゲートのカスタムUIViewControllerAnimatedTransitioningを作成することです。

したがって、より多くのステップを実行することを前提としていますが、結果はよりカスタマイズ可能であり、表示されたビューと一緒にビューから移動するなどの副作用はありません。

したがって、ViewControllerがいくつかあり、プレゼンテーションを行うためのメソッドがあると仮定します。

var presentTransition: UIViewControllerAnimatedTransitioning?
var dismissTransition: UIViewControllerAnimatedTransitioning?    

func showSettings(animated: Bool) {
    let vc = ... create new vc to present

    presentTransition = RightToLeftTransition()
    dismissTransition = LeftToRightTransition()

    vc.modalPresentationStyle = .custom
    vc.transitioningDelegate = self

    present(vc, animated: true, completion: { [weak self] in
        self?.presentTransition = nil
    })
}

presentTransitionそしてdismissTransition、あなたのビューコントローラをアニメーション化するために使用されています。したがって、ViewControllerを次のように採用しますUIViewControllerTransitioningDelegate

extension ViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return presentTransition
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return dismissTransition
    }
}

したがって、最後のステップは、カスタムトランジションを作成することです。

class RightToLeftTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let toView = transitionContext.view(forKey: .to)!

        container.addSubview(toView)
        toView.frame.origin = CGPoint(x: toView.frame.width, y: 0)

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
            toView.frame.origin = CGPoint(x: 0, y: 0)
        }, completion: { _ in
            transitionContext.completeTransition(true)
        })
    }
}

class LeftToRightTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let fromView = transitionContext.view(forKey: .from)!

        container.addSubview(fromView)
        fromView.frame.origin = .zero

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: {
            fromView.frame.origin = CGPoint(x: fromView.frame.width, y: 0)
        }, completion: { _ in
            fromView.removeFromSuperview()
            transitionContext.completeTransition(true)
        })
    }
}

そのコードビューコントローラーは現在のコンテキストで表示され、その時点からカスタマイズを行うことができます。また、カスタムUIPresentationControllerも役立つことがわかります(を使用して渡すUIViewControllerTransitioningDelegate


よくやった!私はしばらくの間すべての答えを試していましたが、何かが正しくありませんでした...私はすべきではなかったものにさえ賛成しました...
Reimond Hill 2018

提示されたVCを却下するときは、単にdismiss(animated:true、completion:nil)と呼びますか?
レイモンドヒル2018

@ReimondHillはい、私は通常のdismissViewControllerを使用しています
HotJard

これは断然最善の解決策です。はい、もう少し複雑ですが、堅牢で、さまざまな条件下で壊れることはありません。受け入れられた答えはハックです。
mmh02 2018年

iPhone 7 +、8 +、X、XMaxを除くすべてのデバイスで完全に機能します。理由は何ですか?vcはフルフレームを取得していません。
UmairAfzal19年

14

カスタムセグエを使用することもできます。

スウィフト5

class SegueFromRight: UIStoryboardSegue {

    override func perform() {
        let src = self.source
        let dst = self.destination

        src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
        dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)

        UIView.animate(withDuration: 0.25,
               delay: 0.0,
               options: UIView.AnimationOptions.curveEaseInOut,
               animations: {
                    dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
            },
                   completion: { finished in
                    src.present(dst, animated: false, completion: nil)
        })
    }
}

現在の状況でのプレゼンテーションで使用する場合は、他の回答よりも
適切な回答

このカスタムセグエを閉じると、デフォルトで元のセグエタイプになります。それを回避する方法はありますか?
アレックスベイリー

1
カスタムセグエは素晴らしいですが、それらはストーリーボードソリューションにすぎません
Fattie

7

これを試して、

    let animation = CATransition()
    animation.duration = 0.5
    animation.type = kCATransitionPush
    animation.subtype = kCATransitionFromRight
     animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    vc.view.layer.addAnimation(animation, forKey: "SwitchToView")

    self.presentViewController(vc, animated: false, completion: nil)

ここでvc、ViewControllerをであるdashboardWorkoutあなたのケースで。


3
おかげで、次のVCは右から左に表示されるのではなく、突然表示されます。アニメーションの長さを変更しましたが、それでも同じです
Umair Afzal 2016

4

「クイックフィックス」CATransitionメソッドを使用したい場合...。

class AA: UIViewController

 func goToBB {

    let bb = .. instantiateViewcontroller, storyboard etc .. as! AlreadyOnboardLogin

    let tr = CATransition()
    tr.duration = 0.25
    tr.type = kCATransitionMoveIn // use "MoveIn" here
    tr.subtype = kCATransitionFromRight
    view.window!.layer.add(tr, forKey: kCATransition)

    present(bb, animated: false)
    bb.delegate, etc = set any other needed values
}

その後 ...

func dismissingBB() {

    let tr = CATransition()
    tr.duration = 0.25
    tr.type = kCATransitionReveal // use "Reveal" here
    tr.subtype = kCATransitionFromLeft
    view.window!.layer.add(tr, forKey: kCATransition)

    dismiss(self) .. or dismiss(bb), or whatever
}

残念ながら、これはすべて正しくありません:(

CATransition この仕事をするために実際に作られているわけではありません。

迷惑なクロスフェードが黒になり、残念ながら効果が損なわれることに注意してください。


多くの開発者(私のような)は本当にを使用するのが好きではありませんNavigationController。多くの場合、特に珍しい複雑なアプリの場合は、アドホックな方法で提示する方が柔軟です。ただし、ナビゲーションコントローラーを「追加」することは難しくありません。

  1. ストーリーボードで、エントリVCに移動し、[埋め込み]-> [ナビゲーションコントローラーに]をクリックします。本当にそれだけです。または、

  2. didFinishLaunchingWithOptions、それはあなたが好むならば、あなたのナビゲーションコントローラを構築するのは簡単です

  3. .navigationControllerプロパティとして常に利用できるので、変数をどこにでも保持する必要はありません-簡単です。

実際、navigationControllerを入手したら、画面間の遷移を行うのは簡単です。

    let nextScreen = instantiateViewController etc as! NextScreen
    navigationController?
        .pushViewController(nextScreen, animated: true)

そして、あなたはすることができpopます。

しかし、それはあなたに標準的なリンゴの「デュアルプッシュ」効果を与えるだけです...

(新しいものがスライドするので、古いものは低速でスライドします。)

一般的に、そして驚くべきことに、あなたは通常、完全なカスタム移行を行うための努力をしなければなりません。

最も単純で最も一般的なムーブオーバー/ムーブオフトランジションが必要な場合でも、完全なカスタムトランジションを実行する必要があります。

幸い、これを行うには、このQAにカットアンドペーストの定型コードがあります... https://stackoverflow.com/a/48081504/294884。2018年明けましておめでとうございます!


3

UIKitをインポートし、UIViewControllerの拡張機能を1つ作成します。

extension UIViewController {
func transitionVc(vc: UIViewController, duration: CFTimeInterval, type: CATransitionSubtype) {
    let customVcTransition = vc
    let transition = CATransition()
    transition.duration = duration
    transition.type = CATransitionType.push
    transition.subtype = type
    transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    present(customVcTransition, animated: false, completion: nil)
}}

簡単な呼び出しの後:

let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromRight)

左から右へ:

let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromleft)

あなたはあなたの好みの期間で期間を変更することができます...


1

これを試して。

let transition: CATransition = CATransition()
transition.duration = 0.3

transition.type = kCATransitionReveal
transition.subtype = kCATransitionFromLeft
self.view.window!.layer.addAnimation(transition, forKey: nil)
self.dismissViewControllerAnimated(false, completion: nil)

1
let transition = CATransition()
    transition.duration = 0.25
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromLeft
    transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    tabBarController?.view.layer.add(transition, forKey: kCATransition)
    self.navigationController?.popToRootViewController(animated: true)

これをアニメーションのボタンクリックイベントに追加しました。Xcode 10.2 swift 4で動作します。
Chilli19年

0

Swiftを使用してiOSでViewControllerを右から左に表示

func FrkTransition() 

{
    let transition = CATransition()

    transition.duration = 2

    transition.type = kCATransitionPush

    transitioningLayer.add(transition,forKey: "transition")

    // Transition to "blue" state

    transitioningLayer.backgroundColor = UIColor.blue.cgColor
    transitioningLayer.string = "Blue"
}

参照者: [ https://developer.apple.com/documentation/quartzcore/catransition] [1 ]


-1

CATransition()を使用して表示される「黒」の遷移を見ずに、Appleの古典的なアニメーションを維持したい場合は、より良い解決策があります。popToViewControllerメソッドを使用するだけです。

必要なviewControllerを探すことができます

self.navigationController.viewControllers // Array of VC that contains all VC of current stack

そのrestorementIdentifierを検索することにより、必要なviewControllerを探すことができます。

注意:たとえば、3つのView Controllerをナビゲートしていて、最後に到達したときに最初にポップしたい場合です。この場合、popToViewControllerが上書きしたため、有効なSECONDビューコントローラーへの参照が失われます。ところで、解決策があります。後で必要になるVCであるpopToViewcontrollerの前に簡単に保存できます。それは私にとって非常にうまくいきました。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.