Używam presentViewController do zaprezentowania nowego ekranu
let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)
Przedstawia nowy ekran od dołu do góry, ale chcę, aby był prezentowany od prawej do lewej bez używania UINavigationController
.
Używam Xib zamiast Storyboard, więc jak mogę to zrobić?
Odpowiedzi:
Nie ma znaczenia, czy jest
xib
lubstoryboard
, że używasz. Zwykle przejście z prawej do lewej strony jest używane, gdy wepchniesz kontroler widoku do kontrolera prezenteraUINavigiationController
.AKTUALIZACJA
Dodano funkcję pomiaru czasu
kCAMediaTimingFunctionEaseInEaseOut
Przykładowy projekt z implementacją Swift 4 dodaną do GitHub
Swift 3 i 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)
Wygląda na to, że
animated
parametr wpresentViewController
metodzie nie ma większego znaczenia w przypadku niestandardowego przejścia. To może mieć dowolną wartość, albotrue
albofalse
.źródło
Pełny kod prezentowania / zwolnienia, 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) } }
źródło
Przeczytaj wszystkie odpowiedzi i nie widzisz prawidłowego rozwiązania. Właściwym sposobem jest utworzenie niestandardowego UIViewControllerAnimatedTransitioning dla prezentowanego delegata VC.
Zakłada więc wykonanie większej liczby kroków, ale wynik jest bardziej konfigurowalny i nie ma żadnych skutków ubocznych, takich jak przejście z widoku razem z prezentowanym widokiem.
Załóżmy więc, że masz ViewController i istnieje metoda prezentacji
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
idismissTransition
służy do animowania kontrolerów widoku. Dlatego dostosowujesz ViewController doUIViewControllerTransitioningDelegate
:extension ViewController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return presentTransition } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return dismissTransition } }
Więc ostatnim krokiem jest utworzenie niestandardowego przejścia:
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) }) } }
W tym widoku kodu kontroler jest prezentowany w bieżącym kontekście, możesz od tego momentu dokonać dostosowań. Możesz również zauważyć, że niestandardowe
UIPresentationController
jest również przydatne (przekazuj użycieUIViewControllerTransitioningDelegate
)źródło
Możesz również użyć niestandardowego przejścia.
Szybki 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) }) } }
źródło
Spróbuj tego,
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)
Oto
vc
kontroler widoku,dashboardWorkout
w twoim przypadku.źródło
Jeśli chcesz użyć metody „szybkiej naprawy” 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 }
i wtedy ...
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 }
Wszystko to niestety nie jest poprawne :(
CATransition
tak naprawdę nie jest stworzony do wykonywania tej pracy.Zauważ, że irytujący krzyż wyblaknie do czerni, co niestety psuje efekt.
Wielu programistów (takich jak ja) naprawdę nie lubi używać
NavigationController
. Często bardziej elastyczne jest prezentowanie w sposób doraźny na bieżąco, szczególnie w przypadku nietypowych i złożonych aplikacji. Jednak „dodanie” kontrolera nawigacji nie jest trudne.po prostu na storyboardzie, przejdź do wpisu VC i kliknij "embed -> in nav controller". Naprawdę to wszystko. Lub,
w
didFinishLaunchingWithOptions
łatwo zbudować kontroler nav jeśli wolisznaprawdę nie musisz nawet nigdzie przechowywać tej zmiennej, ponieważ
.navigationController
jest ona zawsze dostępna jako właściwość - to łatwe.Naprawdę, gdy masz już NavigationController, przejście między ekranami jest trywialne,
let nextScreen = instantiateViewController etc as! NextScreen navigationController? .pushViewController(nextScreen, animated: true)
i możesz
pop
.To jednak daje tylko standardowy efekt „podwójnego naciśnięcia” jabłka ...
(Stary zsuwa się z mniejszą prędkością, podczas gdy nowy ślizga się).
Ogólnie rzecz biorąc, i co zaskakujące, zwykle musisz podjąć wysiłek, aby wykonać w pełni niestandardowe przejście.
Nawet jeśli chcesz po prostu najprostszego, najczęstszego przejścia na ruch / opuszczenie, musisz wykonać w pełni niestandardowe przejście.
Na szczęście, aby to zrobić, w tej kontroli jakości jest trochę kodu standardowego wycinania i wklejania ... https://stackoverflow.com/a/48081504/294884 . Szczęśliwego Nowego Roku 2018!
źródło
zaimportuj UIKit i utwórz jedno rozszerzenie dla 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) }}
po prostym połączeniu:
let vC = YourViewController() transitionVc(vc: vC, duration: 0.5, type: .fromRight)
od lewej do prawej:
let vC = YourViewController() transitionVc(vc: vC, duration: 0.5, type: .fromleft)
możesz zmienić czas trwania z preferowanym czasem trwania ...
źródło
Spróbuj tego.
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)
źródło
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)
źródło
Obecny kontroler widoku od prawej do lewej w iOS przy użyciu Swift
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" }
Refrence By: [ https://developer.apple.com/documentation/quartzcore/catransition][1]
źródło
Mam lepsze rozwiązanie, które zadziałało, jeśli chcesz zachować klasyczną animację Apple, bez oglądania tego „czarnego” przejścia, które widzisz za pomocą CATransition (). Po prostu użyj metody popToViewController.
Możesz poszukać elementu viewController, którego potrzebujesz
self.navigationController.viewControllers // Array of VC that contains all VC of current stack
Możesz poszukać elementu viewController, którego potrzebujesz, wyszukując jego restorationIdentifier.
BĄDŹ OSTROŻNY: na przykład, jeśli nawigujesz przez 3 kontrolery widoku, a kiedy dotrzesz do ostatniego, chcesz otworzyć pierwszy. W takim przypadku utracisz odwołanie do efektywnego kontrolera widoku DRUGIEGO, ponieważ popToViewController go nadpisał. Przy okazji, istnieje rozwiązanie: możesz łatwo zapisać przed popToViewcontroller, VC, którego będziesz potrzebować później. U mnie zadziałało bardzo dobrze.
źródło
To zadziałało dla mnie:
self.navigationController?.pushViewController(controller, animated: true)
źródło