如何使用Swift在iOS中从右到左显示视图控制器


82

我正在使用presentViewController呈现新屏幕

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

这将显示从下到上的新屏幕,但我希望不使用即可从右到左显示UINavigationController

我使用的是Xib而不是情节提要,该怎么办?


简而言之,完整答案:stackoverflow.com/a/48081504/294884
Fattie

Answers:


158

是否使用xibstoryboard正在使用都没关系。通常,当您将视图控制器推入Presentor时,使用从右向左过渡UINavigiationController

更新

新增计时功能 kCAMediaTimingFunctionEaseInEaseOut

示例项目斯威夫特4实现加入GitHub上


迅捷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)


对象

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];


斯威夫特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)

在自定义转换的情况下,方法中的animated参数presentViewController似乎并不重要。它可以是任何值,true或者false


2
我试图在自定义UIStoryboardSegue的perform()方法内使用Swift3代码,问题是-在同一视图上完成了转换,然后出现了第二个视图。有什么想法吗?
Devarshi '16

2
通常,当我使用此方法时,源VC正在逐渐淡出。如何删除该淡入淡出效果,使其具有与推动画一样的效果?
Umair Afzal

1
@UmairAfzal那是窗口的颜色,您需要更改窗口的颜色以避免这种情况。
Abdul Rehman

如何在Swift 3中通过UIModalPresentationStyle.overCurrentContext有效使用此过渡
Mamta

3
如果将“动画”设置为“ true”,它也会有轻微的向上动画。我建议将其设置为“ false”
Rebeloper '18

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

2
Upvoting你的答案,因为它具有解雇功能太
Rebeloper

那里最好的之一!👌
希亚姆

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

presentTransitiondismissTransition用于为视图控制器设置动画。因此,您将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)
        })
    }
}

在当前上下文中显示该代码视图控制器时,您可以从那时开始进行自定义。另外,您可能还会看到customUIPresentationController也很有用(使用传递UIViewControllerTransitioningDelegate


做得好!我试了一段时间所有的答案,有什么不对劲……我什至赞成一个不应该的……
Reimond Hill,

什么时候解散所显示的VC,您只是调用dismiss(animated:true,completion:nil)?
Reimond山

@ReimondHill是的,我只使用普通的dismissViewController
HotJard '18

这是迄今为止最好的解决方案。是的,它有点复杂,但是它很健壮并且在各种情况下都不会损坏。公认的答案是骇客。
mmh02 '18 -10-24

它可以在除iPhone 7 +,8 +,X和XMax之外的所有设备上完美运行。知道为什么吗?vc不能完全显示。
Umair Afzal

14

您还可以使用自定义segue。

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

如果在当前情况下用于演示时,则比其他方法更好地回答
Varun Naharia

取消此自定义segue时,它仍默认为原始segue类型。有没有解决的办法?
Alex Bailey

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)

vcdashboardWorkout您的情况下的viewcontroller 。


3
谢谢,但是下一个VC突然出现了,而不是从右到左。我更改了动画时长,但仍然相同
Umair Afzal

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创建一个扩展:

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中对我有用。–
Chilli

0

使用Swift在iOS中从右到左显示视图控制器

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

如果您想保留Apple的经典动画,而又没有看到使用CATransition()看到的“黑色”过渡,则有一个更好的解决方案对我有用。只需使用popToViewController方法。

您可以在其中寻找所需的viewController

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

您可以通过搜索restoreIdentifier查找所需的viewController。

注意:例如,如果要浏览3个视图控制器,并且到达最后一个时,则要弹出第一个。在这种情况下,您将丢失对有效的SECOND视图控制器的引用,因为popToViewController已覆盖它。顺便说一句,有一个解决方案:您可以在popToViewcontroller之前轻松保存以后需要的VC。它对我很好。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.