Ich habe eine kleine iPhone-App , die einen Navigationscontroller verwendet, um 3 Ansichten anzuzeigen (hier Vollbild ):
Zunächst wird eine Liste der sozialen Netzwerke (Facebook, Google+ usw.) angezeigt:
Anschließend wird ein OAuth-Dialogfeld angezeigt, in dem Sie nach Anmeldeinformationen gefragt werden:
Und (danach ebenfalls UIWebView
) für Berechtigungen:
Schließlich wird der letzte Ansichts-Controller mit Benutzerdetails angezeigt (in der realen App ist dies das Menü, in dem das Multiplayer-Spiel gestartet werden kann):
Das alles funktioniert gut, aber ich habe ein Problem, wenn der Benutzer zurückgehen und ein anderes soziales Netzwerk auswählen möchte:
Der Benutzer berührt die Zurück-Schaltfläche und anstatt die erste Ansicht anzuzeigen, wird die zweite angezeigt, in der er erneut nach OAuth-Anmeldeinformationen / Berechtigungen fragt.
Was kann ich hier machen? Xcode 5.0.2 zeigt eine sehr begrenzte Auswahl für Segmente - Push , Modal (was ich nicht verwenden kann, da es die für mein Spiel benötigte Navigationsleiste verdeckt) und Benutzerdefiniert .
Ich bin ein Neuling in der iOS-Programmierung, aber früher habe ich eine mobile Adobe AIR-App entwickelt. Dort war es möglich, 1) die Ansicht zu ersetzen, anstatt zu drücken, und 2) eine nicht benötigte Ansicht aus dem Navigationsstapel zu entfernen.
Wie mache ich das bitte in einer nativen App?
quelle
sourceViewController.navigationController
in einer Variablen gespeichert und es wurdenil
vor dem letzten Befehl eingegebenperform
- und deshalb hat es bei mir nicht funktioniert. Aber die aktuelle Version funktioniert perfekt, danke! Die Antworten von Lauro und Bhavya sind ebenfalls sehr aufschlussreich.Um die verschiedenen oben genannten Bereiche zu erweitern, ist dies meine Lösung. Es hat folgende Vorteile:
Segue Code:
- (void)perform { // Grab Variables for readability UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; UIViewController *destinationController = (UIViewController*)[self destinationViewController]; UINavigationController *navigationController = sourceViewController.navigationController; // Get a changeable copy of the stack NSMutableArray *controllerStack = [NSMutableArray arrayWithArray:navigationController.viewControllers]; // Replace the source controller with the destination controller, wherever the source may be [controllerStack replaceObjectAtIndex:[controllerStack indexOfObject:sourceViewController] withObject:destinationController]; // Assign the updated stack with animation [navigationController setViewControllers:controllerStack animated:YES]; }
quelle
Das benutzerdefinierte Segment funktionierte bei mir nicht, da ich einen Splash View-Controller hatte und diesen ersetzen wollte. Da es nur einen Ansichts-Controller in der Liste gab,
popToRootViewController
ließ der Splash immer noch auf dem Stapel. Ich habe den folgenden Code verwendet, um den einzelnen Controller zu ersetzen-(void)perform { UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; UIViewController *destinationController = (UIViewController*)[self destinationViewController]; UINavigationController *navigationController = sourceViewController.navigationController; [navigationController setViewControllers:@[destinationController] animated:YES]; }
und jetzt in Swift 4:
class ReplaceSegue: UIStoryboardSegue { override func perform() { source.navigationController?.setViewControllers([destination], animated: true) } }
und jetzt in Swift 2.0
class ReplaceSegue: UIStoryboardSegue { override func perform() { sourceViewController.navigationController?.setViewControllers([destinationViewController], animated: true) } }
quelle
tableViewCell
zu einem erstelltviewController
. Der Übergang wird mit derReplaceSegue
Klasse als benutzerdefiniert festgelegt .die schnelle 2 version von ima747 antwort:
override func perform() { let navigationController: UINavigationController = sourceViewController.navigationController!; var controllerStack = navigationController.viewControllers; let index = controllerStack.indexOf(sourceViewController); controllerStack[index!] = destinationViewController navigationController.setViewControllers(controllerStack, animated: true); }
Wie er erwähnte, hat es die folgenden Vorteile:
quelle
if let
Sicherheit zu erhöhen , können Sie den Index unter bestimmten Bedingungen abrufen. Auf diese Weise müssen Sie die Variable nicht zwangsweise auspacken, was möglicherweise fehleranfällig ist.Für dieses Problem denke ich, dass die Antwort einfach ist
Setzen Sie dann das Array von ViewControllern wie folgt auf den Navigationscontroller zurück:
if let navController = self.navigationController { let newVC = DestinationViewController(nibName: "DestinationViewController", bundle: nil) var stack = navController.viewControllers stack.remove(at: stack.count - 1) // remove current VC stack.insert(newVC, at: stack.count) // add the new one navController.setViewControllers(stack, animated: true) // boom! }
funktioniert perfekt mit Swift 3.
Hoffe, es hilft für einige neue Leute.
Prost.
quelle
Die Abwicklung wäre die am besten geeignete Lösung für dieses Problem. Ich stimme Lauro zu.
Hier ist eine kurze Erklärung zum Einrichten eines Abwicklungsabschnitts von detailsViewController [oder viewController3] zu myAuthViewController [oder viewController1].
Dies ist im Wesentlichen die Vorgehensweise beim Abwickeln des Codes.
Implementieren Sie eine IBAction-Methode in dem viewController, zu dem Sie sich abwickeln möchten (in diesem Fall viewController1). Der Methodenname kann beliebig lang sein, sodass ein Argument vom Typ UIStoryboardSegue erforderlich ist.
@IBAction func unwindToMyAuth(segue: UIStoryboardSegue) { println("segue with ID: %@", segue.Identifier) }
Verknüpfen Sie diese Methode mit dem viewController (3), von dem Sie sich entspannen möchten. Klicken Sie zum Verknüpfen mit der rechten Maustaste (Doppeltipp) auf das Exit-Symbol oben im viewController. Zu diesem Zeitpunkt wird die Methode 'unwindToMyAuth' im Popup-Feld angezeigt. Klicken Sie bei gedrückter Ctrl-Taste von dieser Methode auf das erste Symbol, das viewController-Symbol (ebenfalls oben im viewController in derselben Zeile wie das Exit-Symbol). Wählen Sie die Option 'Manuell', die angezeigt wird.
Wählen Sie in der Dokumentübersicht für dieselbe Ansicht (viewController3) den soeben erstellten Abwicklungsbereich aus. Gehen Sie zum zugewiesenen Inspektor und weisen Sie eine eindeutige Kennung für diesen Abwicklungsabschnitt zu. Wir haben jetzt einen generischen Abwicklungsbereich zur Verwendung bereit.
Jetzt kann der Abwicklungsabschnitt wie jeder andere Abschnitt aus dem Code ausgeführt werden.
performSegueWithIdentifier("unwind.to.myauth", sender: nil)
Dieser Ansatz führt Sie von viewController3 zu viewController1, ohne dass viewController2 aus der Navigationshierarchie entfernt werden muss.
Im Gegensatz zu anderen Segmenten instanziieren Abwicklungssegmente keinen Ansichts-Controller, sondern gehen nur zu einem vorhandenen Ansichts-Controller in der Navigationshierarchie.
quelle
Wie in den vorherigen Antworten erwähnt, sieht es nicht sehr gut aus, wenn Pop nicht animiert und dann animiert gedrückt wird, da der Benutzer den tatsächlichen Prozess sieht. Ich empfehle Ihnen, zuerst animiert zu drücken und dann den vorherigen VC zu entfernen. Wie so:
extension UINavigationController { func replaceCurrentViewController(with viewController: UIViewController, animated: Bool) { pushViewController(viewController, animated: animated) let indexToRemove = viewControllers.count - 2 if indexToRemove >= 0 { viewControllers.remove(at: indexToRemove) } } }
quelle
Hier eine schnelle Swift 4/5-Lösung, indem eine benutzerdefinierte Sequenz erstellt wird, die den Ansichtscontroller (oberster Stapel) durch den neuen ersetzt (ohne Animation):
class SegueNavigationReplaceTop: UIStoryboardSegue { override func perform () { guard let navigationController = source.navigationController else { return } navigationController.popViewController(animated: false) navigationController.pushViewController(destination, animated: false) } }
quelle
Verwenden Sie den Code für die letzte Ansicht des folgenden Codes. Sie können eine andere Schaltfläche verwenden oder eine eigene Schaltfläche anstelle der von mir verwendeten Schaltfläche zum Abbrechen verwenden
- (void)viewDidLoad { [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss:)]; self.navigationItemSetting.leftBarButtonItem = cancelButton; } - (IBAction)dismissSettings:(id)sender { // your logout code for social media selected [self.navigationController popToRootViewControllerAnimated:YES]; }
quelle
setNavigationBarHidden:NO
? Ihr Code funktioniert gut, danke und es ist auch ein guter Ort für den Abmeldecode des sozialen Netzwerks.Was Sie wirklich tun sollten, ist modal zu präsentieren,
UINavigationController
das das soziale NetzwerkUIViewControllers
über Ihrem Menü enthältUIViewController
(das in ein eingebettet werden kann,UINavigationController
wenn Sie möchten). Sobald sich ein Benutzer authentifiziert hat, schließen Sie das soziale NetzwerkUINavigationController
und zeigen Ihr MenüUIViewController
erneut an.quelle
In
swift3
Erstellen einer segue -add Identifikator -add und SET in segue (Storyboard) benutzerdefinierten Klasse von Storyboard Cocoatouch Datei -In benutzerdefinierte Klasse Überschreibung durchführen ()override func perform() { let sourceViewController = self.source let destinationController = self.destination let navigationController = sourceViewController.navigationController // Pop to root view controller (not animated) before pushing if self.identifier == "your identifier"{ navigationController?.popViewController(animated: false) navigationController?.pushViewController(destinationController, animated: true) } }
-Sie müssen auch eine Methode in Ihrem Quellansichtscontroller überschreiben
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { return false }
quelle
Nun, was Sie auch tun können, ist die Verwendung des Unwind View Controller-Materials.
Eigentlich denke ich, dass dies genau das ist, was Sie brauchen.
Überprüfen Sie diesen Eintrag: Wofür sind Unwind-Segmente und wie verwenden Sie sie?
quelle
Das hat bei mir in Swift 3 funktioniert:
class ReplaceSegue: UIStoryboardSegue { override func perform() { if let navVC = source.navigationController { navVC.pushViewController(destination, animated: true) } else { super.perform() } } }
quelle
Wie wäre es damit :) Ich jetzt ist es eine alte Frage, aber das wird als Zauber wirken:
UIViewController *destinationController = [[UIViewController alloc] init]; UINavigationController *newNavigation = [[UINavigationController alloc] init]; [newNavigation setViewControllers:@[destinationController]]; [[[UIApplication sharedApplication] delegate] window].rootViewController = newNavigation;
quelle