简体   繁体   English

iOS 转场 - 从左到右 -

[英]iOS Segue - Left to Right -

I've read the other posts on segues but none solve my question.我已经阅读了关于 segue 的其他帖子,但没有一个能解决我的问题。

Simply put, my ViewController s are ordered, like a book.简单地说,我的ViewController是有序的,就像一本书。 I want backward transitions (example: from page 9 to 8) to always present (slide over) from left to right.我希望向后过渡(例如:从第 9 页到第 8 页)始终从左到右呈现(滑过)。 I want forward transitions (from page 9 to 10) to present from right to left.我希望向前过渡(从第 9 页到第 10 页)从右到左呈现。

Yes, my nav-controller back button (top left) presents like this if you are paging through page by page.是的,如果您逐页翻阅,我的导航控制器后退按钮(左上角)会显示这样。 However, if you jump in from an Index then the back function on the nav controller takes you back to the index.但是,如果您从索引跳转,则导航控制器上的返回功能会将您带回索引。

My objective is that if a user jumps to page 9 (for example) from an index, then swipes right, it'll flick the page off to the right and show page 8. Once on page 8, if they flick left the page will get flicked off to the left and they'll be on page 9 again.我的目标是,如果用户从索引跳转到第 9 页(例如),然后向右滑动,它会将页面向右滑动并显示第 8 页。一旦在第 8 页上,如果他们向左滑动,页面将向左轻弹,它们将再次出现在第 9 页。

All my ViewController s are by, default, presenting by sliding in from right to left.默认情况下,我所有的ViewController都是通过从右向左滑动来呈现的。

Example: Think of it like a book, if I use the Index to hop to chapter 4, then swipe right and pop a view from the stack, I'll be back at the Index.示例:把它想象成一本书,如果我使用索引跳到第 4 章,然后向右滑动并从堆栈中弹出一个视图,我将回到索引处。 But if you're on Chapter 4, page 394 and you swipe right, you don't want to go back to the index!但是,如果您在第 4 章第 394 页上向右滑动,您就不想返回索引! You want to go to the last page of chapter 3, page 393!你要翻到第3章的最后一页,第393页! So the nav stack is no help to me.所以导航堆栈对我没有帮助。

End Example结束示例

Details: 1. I'm using the new Xcode "Show" on button-tap to switch between ViewControllers.详细信息: 1. 我正在使用新的 Xcode“显示”按钮点击在 ViewControllers 之间切换。

  1. I'm using a navigation controller, for the top-left "Back" button functionality.我正在使用导航控制器,用于左上角的“后退”按钮功能。 This uses the nav stack and works fine.这使用导航堆栈并且工作正常。

  2. However I have my own custom nav-bar at the bottom (Back Button, Home Button, Index Button, Forward Button) and gestures.但是,我在底部有自己的自定义导航栏(后退按钮、主页按钮、索引按钮、前进按钮)和手势。 These are what I want to have book-like functionality with.这些就是我想要具有书本功能的东西。

  3. Coding in swift.快速编码。

  4. Working with Xcode 6.3使用 Xcode 6.3

I've read that there's animation code.我读过有动画代码。 I've read there's in depth programatic transitions that can be used.我已经阅读了可以使用的深度编程转换。 It just seems crazy that there's no simple way to just select the segues I want to present from the left and easily reverse the animation.没有简单的方法可以从左侧选择我想要呈现的转场并轻松反转动画,这似乎很疯狂。

Thanks!谢谢!

Attempt log:尝试日志:

I tried DCDC's code:
    UIView.transitionWithView(self.window!, duration: 0.5, options:.TransitionFlipFromLeft, animations: { () -> Void in
            self.window!.rootViewController = mainVC
            }, completion:nil)

This error is returned when I insert DCDC's code into an IBAction for my back-swipe当我将 DCDC 的代码插入IBAction以进行向后滑动时,会返回此错误

当我将 DCDC 的代码插入 IBAction 以进行向后滑动时,会返回此错误

This is how I achieve the effect without requiring a nav-controller.这就是我在不需要导航控制器的情况下实现效果的方式。 Try this instead:试试这个:

Swift 4:斯威夫特 4:

import UIKit
class SegueFromLeft: 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: .curveEaseInOut,
                         animations: {
                                dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
                                },
                        completion: { finished in
                                src.present(dst, animated: false, completion: nil)
                                    }
                        )
    }
}

Swift 3:斯威夫特 3:

import UIKit

class SegueFromLeft: UIStoryboardSegue
{
    override func perform()
    {
        let src = self.sourceViewController
        let dst = self.destinationViewController

        src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
        dst.view.transform = CGAffineTransformMakeTranslation(-src.view.frame.size.width, 0)

        UIView.animateWithDuration(0.25,
            delay: 0.0,
            options: UIViewAnimationOptions.CurveEaseInOut,
            animations: {
                dst.view.transform = CGAffineTransformMakeTranslation(0, 0)
            },
            completion: { finished in
                src.presentViewController(dst, animated: false, completion: nil)
            }
        )
    }
}

Then in the storyboard, click on the segue you'd like to change.然后在情节提要中,单击要更改的转场。 In the attributes inspector change the type to 'Custom' and change the class to 'SegueFromLeft'在属性检查器中将类型更改为“自定义”并将类更改为“SegueFromLeft”

Here is a custom-segue class you can use to perform a left-to-right segue in Swift.这是一个自定义转场类,可用于在 Swift 中执行从左到右的转场。 It requires QuartzCore framework and minimal animation.它需要 QuartzCore 框架和最少的动画。

Swift 2.2斯威夫特 2.2

import UIKit
import QuartzCore

class SegueFromLeft: UIStoryboardSegue {

    override func perform() {
        let src: UIViewController = self.sourceViewController
        let dst: UIViewController = self.destinationViewController
        let transition: CATransition = CATransition()
        let timeFunc : CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.duration = 0.25
        transition.timingFunction = timeFunc
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        src.navigationController!.view.layer.addAnimation(transition, forKey: kCATransition)
        src.navigationController!.pushViewController(dst, animated: false)
    }

}

Swift 3.0斯威夫特 3.0

import UIKit
import QuartzCore

class SegueFromLeft: UIStoryboardSegue {

    override func perform() {
        let src: UIViewController = self.source
        let dst: UIViewController = self.destination
        let transition: CATransition = CATransition()
        let timeFunc : CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.duration = 0.25
        transition.timingFunction = timeFunc
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        src.navigationController!.view.layer.add(transition, forKey: kCATransition)
        src.navigationController!.pushViewController(dst, animated: false)
    }
}

The "Back" button will still appear in the navigation bar on the transitioned view controller, but you can easily disable/configure the navigation controller for that view controller. “返回”按钮仍将出现在转换后的视图控制器的导航栏中,但您可以轻松禁用/配置该视图控制器的导航控制器。

Updated accepted answer in Swift 3:更新了 Swift 3 中接受的答案:

import UIKit

class SegueFromLeft: 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: UIViewAnimationOptions.curveEaseInOut,
            animations: {
                dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
            },
            completion: { finished in
                src.present(dst, animated: false, completion: nil)
            }
        )
    }
}

You can use of the predeclared type of transition in transitionWithView method您可以在 transitionWithView 方法中使用预先声明的过渡类型

UIView.transitionWithView(self.window!, duration: 0.5, options:.TransitionFlipFromLeft, animations: { () -> Void in
            self.window!.rootViewController = mainVC
            }, completion:nil)

I guess .TransitionFlipFromLeft is the desired one我猜 .TransitionFlipFromLeft 是想要的

To complete the task, drag a new view controller to your storyboard and name it with some id.要完成任务,请将一个新的视图控制器拖到您的故事板中,并用一些 id 命名它。 This is going to be the destination of the transition.这将是过渡的目的地。

then instantiate this view controller from code然后从代码实例化这个视图控制器

let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let mainVC = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController

You can do this either inside the IBAction or for example in ViewDidLoad but probably IBAction will be the better choice.您可以在 IBAction 内部或例如在 ViewDidLoad 中执行此操作,但可能 IBAction 将是更好的选择。 Pay attention to type the correct identifiers for both storyboard and view controller.注意为故事板和视图控制器输入正确的标识符。 Also, you have to declare your appDelegate instance.此外,您必须声明您的 appDelegate 实例。 Here is the implemented IBAction这是实现的 IBAction

@IBAction func push(sender: UIButton) {

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let mainVC = storyboard.instantiateViewControllerWithIdentifier("secondVC") as! UIViewController
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    UIView.transitionWithView(appDelegate.window!, duration: 0.5, options: .TransitionFlipFromLeft , animations: { () -> Void in
        appDelegate.window!.rootViewController = mainVC
        }, completion:nil)
}

If this is not what you have expected, probably you might want to make a custom animation.如果这不是您所期望的,您可能想要制作自定义动画。 This article is really helpful : http://mathewsanders.com/animated-transitions-in-swift/这篇文章真的很有帮助: http : //mathewsanders.com/animated-transitions-in-swift/

Accepted answer updated for Swift 3 (as of Jun 2017)已为Swift 3更新的已接受答案(截至 2017 年 6 月)

Segue from left to right从左到右转

import UIKit

class SegueFromLeft: UIStoryboardSegue {
    override func perform() {
        let src = self.source       //new enum
        let dst = self.destination  //new enum

        src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
        dst.view.transform = CGAffineTransform(translationX: -src.view.frame.size.width, y: 0) //Method call changed
        UIView.animate(withDuration: 0.25, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations: { 
            dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
        }) { (finished) in
            src.present(dst, animated: false, completion: nil) //Method call changed
        }
    }
}

Segue from right to left从右到左转

import UIKit

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*2, y: 0) //Double the X-Axis
        UIView.animate(withDuration: 0.25, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations: { 
            dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
        }) { (finished) in
            src.present(dst, animated: false, completion: nil)
        }
    }
}

It sounds like you are just trying to pop a view controller off the UINavigationController's stack, just like the default back button would.听起来您只是想从 UINavigationController 的堆栈中弹出一个视图控制器,就像默认的后退按钮一样。

You can do one of two things.你可以做两件事之一。 The easiest is to connect your custom back button to an IBAction that calls popViewControllerAnimated():最简单的方法是将自定义后退按钮连接到调用 popViewControllerAnimated() 的 IBAction:

@IBAction func tappedCustomBackButton(sender: AnyObject) {
    self.navigationController?.popViewControllerAnimated(true)
}

Or you can create an unwind segue from your second view controller back to your first.或者你可以创建一个从你的第二个视图控制器回到你的第一个视图控制器的unwind segue

Segue from right.You can override the perform function in segue like below. Segue 从右边开始。您可以像下面这样覆盖 segue 中的执行功能。 put this function inside a custom segue class and assign this class to the segue.将此函数放在自定义 segue 类中,并将此类分配给 segue。 it will work for both controllers with navigation controller and without navigation controller它适用于带导航控制器和不带导航控制器的控制器

override func perform()
{
    let src = self.sourceViewController
    print(src)
    let dst = self.destinationViewController
    print(dst)

    src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
    dst.view.transform = CGAffineTransformMakeTranslation(src.view.frame.size.height, 0)

    UIView.animateWithDuration(0.35,
                               delay: 0.0,
                               options: UIViewAnimationOptions.CurveEaseInOut,
                               animations: {
                                dst.view.transform = CGAffineTransformMakeTranslation(0, 0)
        },
                               completion: { finished in
                                if let navController = src.navigationController {
                                    navController.pushViewController(dst, animated: false)

                                } else {
                                    src.presentViewController(dst, animated: false, completion: nil)
                                }            }
    )
}

if you want the segue from left then use this如果你想从左边开始转场,那么使用这个

CGAffineTransformMakeTranslation(-src.view.frame.size.height, 0)

In my case I used to make a sidebar menu...就我而言,我曾经制作侧边栏菜单...

I created a new view controller and two customs segues我创建了一个新的视图控制器和两个自定义 segue

TO OPEN THE MENU:打开菜单:

import Foundation
import UIKit

class SegueFromLeft: UIStoryboardSegue {

  override func perform() {

    let src = self.source as UIViewController
    let dst = self.destination as UIViewController

    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: UIViewAnimationOptions.curveEaseInOut,
                               animations: {
                                dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
    },
                               completion: { finished in
                                src.present(dst, animated: false, completion: nil)
    }
    )

}

}

TO CLOSE THE MENU:关闭菜单:

import Foundation
import UIKit

class SegueFromRight: UIStoryboardSegue {

override func perform() {

    let src = self.source as UIViewController
    let dst = self.destination as UIViewController

    src.view.superview?.insertSubview(dst.view, belowSubview: src.view)
    src.view.transform = CGAffineTransform(translationX: 0, y: 0)

    UIView.animate(withDuration: 0.25,
                               delay: 0.0,
                               options: UIViewAnimationOptions.curveEaseInOut,
                               animations: {
                                src.view.transform = CGAffineTransform(translationX: -src.view.frame.size.width, y: 0)
    },
                               completion: { finished in
                                src.dismiss(animated: false, completion: nil)
    }
    )
}
}

I hope it helped you...我希望它对你有帮助...

Updated the accepted answer to Swift 4:将接受的答案更新为 Swift 4:

class SegueFromLeft: 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: UIViewAnimationOptions.curveEaseInOut,
                               animations: {
                                dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
    },
                               completion: { finished in
                                src.present(dst, animated: false, completion: nil)
    })
     }
}

Feel free to copy this into the accepted answer and delete this comment.随意将其复制到已接受的答案中并删除此评论。 (It's a straight update, nothing new.) (这是一个直接的更新,没什么新鲜的。)

有点晚了,我知道党...它self.view.windowself.window

Hey guy I have complete solution just copy and past this code written swift 3.嘿伙计,我有完整的解决方案,只需复制并粘贴 swift 3 编写的代码即可。

func menu(){
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "MyAccountViewController") as! MyAccountViewController

    let transition: CATransition = CATransition()
    let timeFunc : CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    transition.duration = 0.5
    transition.timingFunction = timeFunc
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromLeft
    self.navigationController?.view.layer.add(transition, forKey: kCATransition)
    self.navigationController?.pushViewController(vc, animated: false)
}

Note: Change the name of your ViewController with "MyAccountViewController" text.注意:使用“MyAccountViewController”文本更改您的 ViewController 的名称。

To create a "back button" like animation, use this.要创建类似动画的“后退按钮”,请使用它。

class SegueRightToLeft: UIStoryboardSegue {

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

    src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
    dst.view.transform = CGAffineTransform(translationX: -src.view.frame.size.width/2, y: 0) 
    //slice the x axis translation in half

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM