Swift kullanarak iOS'ta sağdan sola görüntüleme denetleyicisi nasıl gösterilir


83

Yeni ekranı sunmak için presentViewController kullanıyorum

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

Bu, aşağıdan yukarıya yeni bir ekran sunuyor ancak kullanmadan sağdan sola sunulmasını istiyorum UINavigationController.

Film şeridi yerine Xib kullanıyorum, bunu nasıl yapabilirim?


Yanıtlar:


160

Çünkü eğer fark etmez xibveya storyboardkullandığınız söyledi. Normalde, bir görünüm denetleyicisini sunum yapanlara ittiğinizde sağdan sola geçiş kullanılır UINavigiationController.

GÜNCELLEME

Zamanlama işlevi eklendi kCAMediaTimingFunctionEaseInEaseOut

Örnek proje ile Swift 4 uygulanmasına GitHub'dan eklendi


Swift 3 ve 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)

Yöntemdeki animatedparametrenin presentViewControllerbu özel geçiş durumunda gerçekten önemi yok gibi görünüyor . Herhangi bir değerde trueveya olabilir false.


2
Swift3 kodunu özel bir UIStoryboardSegue'nun perform () yöntemi içinde kullanmaya çalıştım, sorun şu - geçiş aynı görünümde yapılıyor ve ardından ikinci görünüm beliriyor. Bununla ilgili herhangi bir fikrin var mı?
Devarshi

2
uEğer bu yöntemi kullandığımda, kaynak VC kayboluyor Bu solma efektini nasıl kaldırabilirim ve tıpkı push animasyonu gibi olmasını sağlayabilirim?
Umair Afzal

1
@UmairAfzal Pencerenin rengi bu, bundan kaçınmak için pencerenin rengini değiştirmeniz gerekiyor.
Abdul Rehman

Swift 3'te UIModalPresentationStyle.overCurrentContext ile bu geçiş etkili bir şekilde nasıl kullanılır
Mamta

3
Eğer "canlandırılmış" ı "doğru" olarak görürseniz, hafif bir yukarı doğru animasyonu da olacaktır. Bunu "yanlış" olarak ayarlamanızı öneririm
Rebeloper

68

Sunum / görevden alma için eksiksiz kod, 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)
    }
}

2
Lütfen daha spesifik ol. Daha fazla açıklamak !
Emm

3
Yanıtı reddetme işlevine sahip olduğu için oylama
Rebeloper

1
Orada en iyilerden biri !! 👌
Shyam

44

Tüm cevapları okuyun ve doğru çözümü göremiyorum. Bunu yapmanın doğru yolu, sunulan VC temsilcisi için özel UIViewControllerAnimatedTransitioning yapmaktır.

Bu nedenle, daha fazla adım atılacağını varsayar, ancak sonuç daha özelleştirilebilir ve sunulan görünümle birlikte görünümden hareket etmek gibi bazı yan etkileri yoktur.

Bu nedenle, bazı ViewController'ınız olduğunu ve sunum yapmak için bir yöntem olduğunu varsayalım.

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
    })
}

presentTransitionve dismissTransitiongörünüm denetleyicilerinize animasyon uygulamak için kullanılır. Böylece ViewController'ınızı aşağıdakilere uyarlarsınız UIViewControllerTransitioningDelegate:

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

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

Dolayısıyla son adım, özel geçişinizi oluşturmaktır:

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)
        })
    }
}

Kod görünümü denetleyicisinin mevcut bağlam üzerinden sunulması, bu noktadan itibaren özelleştirmelerinizi yapabilirsiniz. Ayrıca özelin UIPresentationControllerde yararlı olduğunu görebilirsiniz (kullanmaya devam edin UIViewControllerTransitioningDelegate)


Aferin! Bir süredir tüm cevapları deniyordum ve doğru olmayan bir şey vardı ... Olmaması gereken Birine bile oy verdim ...
Reimond Hill

Sunulan VC'yi ne zaman kapatırsanız, sadece dismiss (animasyonlu: true, complete: nil) mı çağırırsınız ???
Reimond Hill

@ReimondHill evet, sadece sıradan dismissViewController kullanıyorum
HotJard

Bu, açık ara en iyi çözümdür. Evet, biraz daha karmaşık, ancak sağlam ve çeşitli koşullar altında kırılmayacak. Kabul edilen cevap bir kesmedir.
mmh02

İPhone 7+, 8+, X, XMax dışındaki tüm cihazlarda mükemmel çalışıyor. Herhangi bir fikrin neden? vc tam kareyi almıyor.
Umair Afzal

14

Özel segmenti de kullanabilirsiniz.

Swift 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)
        })
    }
}

Sunumda mevcut bağlamda kullanılırsa diğerinden daha iyi cevap
Varun Naharia

Bu özel segmenti kapatırken, yine de varsayılan olarak orijinal segment tipindedir. Bunun etrafında bir yol var mı?
Alex Bailey

1
özel bölümler harika olsa da - bunlar yalnızca bir storyboard çözümü
Fattie

7

Bunu dene,

    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)

İşte sizin durumunuzda vcviewcontroller dashboardWorkout.


3
Teşekkürler, ama bir sonraki VC sağdan sola görünmek yerine aniden ortaya çıkıyor. Animasyon süresini değiştirdim ama yine de aynı
Umair Afzal

4

"Hızlı düzeltme" CATransition yöntemini kullanmak istiyorsanız ....

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
}

ve sonra ...

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
}

Bunların hepsi maalesef gerçekten doğru değil :(

CATransition gerçekten bu işi yapmak için yapılmadı.

Sinir bozucu haçın siyaha döneceğini ve maalesef etkiyi mahvedeceğini unutmayın.


Çoğu geliştirici (benim gibi) kullanmayı gerçekten sevmiyor NavigationController. Çoğunlukla, özellikle alışılmadık ve karmaşık uygulamalar için, siz ilerledikçe yalnızca geçici bir şekilde sunum yapmak daha esnektir. Ancak, bir nav denetleyicisi "eklemek" zor değildir.

  1. basitçe film şeridinde, VC girişine gidin ve "yerleştir -> nav denetleyicisine" tıklayın. Gerçekten bu kadar. Veya,

  2. içinde didFinishLaunchingWithOptionso dilerseniz nav denetleyicisi oluşturmak kolaydır

  3. .navigationControllerHer zaman bir özellik olarak mevcut olduğu gibi , değişkeni herhangi bir yerde tutmanıza bile gerek yoktur - kolaydır.

Gerçekten, bir navigationController'a sahip olduğunuzda, ekranlar arasında geçiş yapmak önemsizdir,

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

ve yapabilirsin pop.

Ancak bu size yalnızca standart elma "ikili itme" efektini verir ...

(Yenisi kayarken, eskisi daha düşük bir hızda kayar.)

Genel olarak ve şaşırtıcı bir şekilde, genellikle tam bir özel geçiş yapmak için çaba sarf etmeniz gerekir.

Yalnızca en basit, en yaygın olan geçiş / taşıma geçişini isteseniz bile, tam bir özel geçiş yapmanız gerekir.

Neyse ki, bunu yapmak için bu KG'de bazı kes ve yapıştır standart kodlar var ... https://stackoverflow.com/a/48081504/294884 . Mutlu yıllar 2018!


3

UIKit'i içe aktarın ve UIViewController için bir uzantı oluşturun:

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)
}}

basit aramadan sonra:

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

soldan sağa:

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

süreyi tercih ettiğiniz süre ile değiştirebilirsiniz ...


1

Bunu dene.

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)

Bunu, animasyon için düğme tıklanan etkinliğime ekledim. Benim için Xcode 10.2 swift 4'te çalışıyor.
Chilli

0

Swift kullanarak iOS'ta görüntü denetleyicisini sağdan sola sunun

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"
}

Referans Gönderen: [ https://developer.apple.com/documentation/quartzcore/catransition][1]


-1

CATransition () kullanarak gördüğünüz "siyah" geçişi görmeden, Apple'ın klasik animasyonunu sürdürmek istiyorsanız, benim için işe yarayan daha iyi bir çözümüm var. PopToViewController yöntemini kullanmanız yeterlidir.

İhtiyacınız olan viewController'ı arayabilirsiniz.

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

RestorationIdentifier'ı arayarak ihtiyacınız olan viewController'ı arayabilirsiniz.

DİKKATLİ OLUN: örneğin, 3 görünüm kontrolöründe geziniyorsanız ve sonuncuya vardığınızda ilkini açmak istiyorsunuz. Bu durumda, popToViewController bunun üzerine yazdığı için, etkili İKİNCİ görünüm denetleyicisine başvuruyu kaybedeceksiniz. BTW, bir çözüm var: popToViewcontroller'dan önce kolayca kaydedebilirsiniz, daha sonra ihtiyaç duyacağınız VC. Benim için çok iyi çalıştı.


-4

Bu benim için çalıştı:

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

Gezinti yığınına itmek istemedim.
Umair Afzal
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.