[英]How to present view controller from right to left in iOS using Swift
我正在使用 presentViewController 來呈現新屏幕
let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)
這從下到上顯示了新屏幕,但我希望它從右到左顯示而不使用UINavigationController
。
我正在使用 Xib 而不是故事板,所以我該怎么做?
您使用的是xib
還是storyboard
都沒有關系。 通常,當您將視圖控制器推入UINavigiationController
的UINavigiationController
時,會使用從右到左的過渡。
更新
添加計時功能kCAMediaTimingFunctionEaseInEaseOut
斯威夫特 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)
在這種自定義轉換的情況下, presentViewController
方法中的animated
參數似乎並不重要。 它可以是任何值, true
或false
。
顯示/關閉的完整代碼,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)
}
}
閱讀所有答案,但看不到正確的解決方案。 正確的做法是為呈現的 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
傳入)
您還可以使用自定義轉場。
斯威夫特 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)
})
}
}
試試這個,
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
是視圖控制器,在您的情況下是dashboardWorkout
。
導入 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)
您可以使用您喜歡的持續時間更改持續時間...
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
。 通常,在進行時以臨時方式呈現更靈活,特別是對於不尋常和復雜的應用程序。 然而,“添加”一個導航控制器並不難。
或者,如果你喜歡
在didFinishLaunchingWithOptions
,很容易在代碼中添加導航控制器
您甚至不需要將變量保留在任何地方,因為.navigationController
始終可以作為屬性使用 - 很簡單。
真的,一旦你有了一個導航控制器,在屏幕之間進行轉換就很簡單了,
let nextScreen = instantiateViewController etc as! NextScreen
navigationController?
.pushViewController(nextScreen, animated: true)
你可以pop
.
(舊的以較低的速度滑落,而新的則滑行。)
通常,令人驚訝的是,您通常必須努力進行完整的自定義過渡。
即使您只想要最簡單、最常見的移動/移動過渡,您也必須進行完整的自定義過渡。
幸運的是,要做到這一點,這個 QA 上有一些剪切和粘貼樣板代碼...... https://stackoverflow.com/a/48081504/294884 。 2018 年新年快樂!
試試這個。
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)
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)
使用 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]
// Never Easy than this before :)
// you just need to add a Static function for navigation transition
// This Code is recommended for the view controller.
public class CustomNavigation: UIViewController {
public override func loadView() {
super.loadView();
}
public override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true);
}
public static func segueNavToLeft(view: UIView) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
}
public static func segueNavToRight(view: UIView) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
}
}
// simply call in your viewcontroller:
func moveToRight() {
CustomNavigation.segueNavToRight(view: view)
let controller = self.storyboard?.instantiateViewController(withIdentifier: "id") as! YourViewController
let navigationController = UINavigationController(rootViewController: YourViewController)
navigationController.modalPresentationStyle = .fullScreen
self.present(navigationController, animated: false, completion: nil)
}
func moveToLeft() {
CustomNavigation.segueNavToLeft(view: view)
self.dismiss(animated: true, completion: nil)
}
class RightToLeftPresentationController: UIPresentationController {
lazy var blackView: UIView = {
let view = UIView()
view.frame = self.containerView?.bounds ?? .zero
view.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.5)
return view
}()
// MARK:- Presentation
override func presentationTransitionWillBegin() {
self.containerView?.addSubview(blackView)
self.presentingViewController.transitionCoordinator?
.animate(alongsideTransition: { _ in
self.blackView.alpha = 0.5
}, completion: nil)
}
// MARK:- Dismiss
override func dismissalTransitionWillBegin() {
UIView.animate(withDuration: 0.25) {
self.blackView.alpha = 0
}
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
if completed {
blackView.removeFromSuperview()
}
}
}
class RightToLeftPresentationSegue: UIStoryboardSegue {
override func perform() {
destination.modalPresentationStyle = .custom
destination.transitioningDelegate = self
source.present(destination, animated: true)
}
}
extension RightToLeftPresentationSegue: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let controller = RightToLeftPresentationController(presentedViewController: presented, presenting: presenting)
presented.transitioningDelegate = controller
return controller
}
}
extension RightToLeftPresentationController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return RightToLeftTransition()
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return LeftToRightTransition()
}
}
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)
})
}
}
如果您想保留 Apple 的經典動畫,而沒有看到使用 CATransition() 看到的“黑色”過渡,我有一個更好的解決方案對我有用。 只需使用 popToViewController 方法。
您可以在其中查找所需的 viewController
self.navigationController.viewControllers // Array of VC that contains all VC of current stack
您可以通過搜索它的 restoreIdentifier 來查找您需要的 viewController。
小心:例如,如果您正在瀏覽 3 個視圖控制器,並且在到達最后一個時想要彈出第一個。 在這種情況下,您將失去對有效 SECOND 視圖控制器的引用,因為 popToViewController 已經覆蓋了它。 順便說一句,有一個解決方案:您可以在 popToViewcontroller 之前輕松保存您以后需要的 VC。 它對我非常有效。
這對我有用:
self.navigationController?.pushViewController(controller, animated: true)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.