2016-04-05 4 views
0

Zunächst tut mir leid, wenn der Titel ein wenig verwirrend ist, werde ich versuchen, es besser zu erklären.Wie wird ViewController an NavigationController gepusht, wenn UITabBarItem programmgesteuert geklickt wird?

Ich verwende StoryBoard nicht in meiner Anwendung, also wird alles programmgesteuert durchgeführt.

So habe ich ein UITabBarController, die die rootViewController meine Anwendung ist, wie in den AppDelegate definiert:

window?.rootViewController = CustomTabBarController() 

Wie Sie sehen können, die maßgeschneiderte TabBar- definiert ist, wie in der Klasse CustomTabBar folgen:

class CustomTabBarController: UITabBarController { 

override func viewDidLoad() { 

    super.viewDidLoad() 

    let mainController = MainViewController() 
    let mainNavigationController = UINavigationController(rootViewController: mainController) 
    mainNavigationController.title = "Home" 
    mainNavigationController.tabBarItem.image = UIImage(named: "icon_home") 

    let searchController = SearchViewController() 
    let searchNavigationController = UINavigationController(rootViewController: searchController) 
    searchNavigationController.title = "Search" 
    searchNavigationController.tabBarItem.image = UIImage(named: "icon_search") 

    // I have four items in the TabBar, all defined the same way as above. 
    //I removed them to keep the code a bit shorter. 

    viewControllers = [mainNavigationController, cameraNavigationController, searchNavigationController, profileNavigationController] 
     } 
    } 

Grundsätzlich ist die TabBar sieht wie folgt:

enter image description here

Wenn ich also auf ein TabItem klicke, erscheint die NavigationController für das spezifische TabItem mit seiner rootViewController; hier funktioniert alles gut.

Der root View Controller für die Kamera ist jedoch Vollbild, dh die TabBar ist für den Benutzer nicht sichtbar. Ich habe eine Schließen-Schaltfläche in der Ansicht hinzugefügt, damit der Benutzer die Ansicht "beenden" kann. Das Problem ist: Da jedes Element über einen eigenen Navigationscontroller verfügt, ist der CameraViewController beim Auswählen des Kameraelements der erste im Stapel NavigationController. Daher kann ich ihn nicht aufrufen, wenn der Benutzer auf die Schaltfläche Schließen klickt.

Ich habe es geschafft, mit dieser answer einen Weg zu finden.

//close button clicked 
self.tabBarController.selectedIndex = 0; 

Es funktioniert aber auf diese Weise wird der Benutzer jedes Mal auf die gleiche Registerkarte "umgeleitet".

Was ich tun möchte, ist "umleiten" den Benutzer auf die vorherige Registerkarte, in der er war. Zum Beispiel sagen wir, er war in "Search" und dann klickte er auf die Kamera TabItem, wenn er beschließt zu schließen, er wird wieder im Bereich "Suche" sein.

Eine Lösung wäre, eine Variable zu haben, die die tatsächliche Position des ViewControllers speichert, also wenn ich auf die Schaltfläche schließe, setze ich den ausgewählten Index einfach auf diese Variable. Ich denke jedoch nicht, dass das sehr elegant ist.

Eine andere wäre, nur drei haben NavigationController (die eine für die Kamera zu löschen) und nur Schiebe-/poping die CameraViewController auf dem tatsächlichen NavigationController (die auf dem Abschnitt ändert sich in Abhängigkeit der Benutzer). Diese Lösung scheint besser zu sein, aber ich kann keinen Weg finden, es zum Laufen zu bringen. Ich habe versucht, die Funktion didSelectViewController zu implementieren und zu überprüfen, ob es gleich dem cameraViewController ist, (wenn wahr) nur drücken Sie es auf den tatsächlichen NavigationController. Es funktioniert nicht, da die tatsächliche NavigationController "Null" ist, wenn ich versuche, diese Aktion durchzuführen.

Meine Frage ist: Was ist der beste Weg, um die Aufgabe zu erfüllen?

Vielen Dank für Ihre Zeit und Entschuldigung für die lange Post.

EDIT 2:

Also habe ich versucht, die Lösung von Joe Benton vorgeschlagen, die Kommentare ähnlich ist I erhalten.

Die Idee ist, die Kamera Bildschirm modal mit shouldSelectViewController, seinen Code war in Objective-C, so ist hier die Swift-2-Version präsentieren zu können:

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool { 
    if viewController == cameraViewController { 
     self.presentViewController(cameraViewController, animated: true, completion: nil) 
     return false 
    } 
    return true 
    } 
} 

Wie Sie sehen können, stelle ich die ViewController direkt und nicht a NavigationController aber das ist ein Detail.

Vergessen Sie nicht von UITabBarControllerDelegate wie so zu erben:

class CustomTabBarController: UITabBarController, UITabBarControllerDelegate 

Und die Delegierten selbst festgelegt wie folgt:

self.delegate = self 

Diese Lösung ist jedoch nicht funktioniert, wenn Sie versuchen, diese Code und wählen Sie die CameraTab, erhalten Sie folgende Fehlermeldung:

Application tried to present modally an active controller UITabBarController 

Nach ein wenig Online-Suche scheint ich, dass Sie nicht modal ein ViewController präsentieren können, die von der TabBarController verwendet wird, bedeutet, dass Sie nicht presentViewController für eine viewController vorher auf diese Weise definiert verwenden können:

viewControllers = [mainNavigationController, cameraViewController, searchNavigationController, profileNavigationController] 

Sie können lernen, weitere Informationen here

also, was ich tat, war zwei CameraViewController an der Spitze der Klasse zu instanziiert (so kann ich darauf zugreifen, wo immer ich will) so:

class CustomTabBarController: UITabBarController, UITabBarControllerDelegate { 

    let cameraControllerTest = CameraViewController() 
    let cameraViewController = CameraViewController() 

    override func viewDidLoad() {...} 
    ... 
} 

Dann fügte ich einen von ihnen in das ViewControllers Array ein, so dass es auf dem UITabBarController

erscheint, egal, welches.

Danach wird in der shouldSelectViewController Funktion, überprüfen Sie einfach die Registerkarte geklickt wurde, wenn es die Instanz der CameraViewController Sie in Ihrem TabBar Array ist, man muss nur die andere Instanz präsentieren, die nicht in dem Array ist, sonst, Du gibst nur wahr zurück. Es sieht wie folgt aus:

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool { 
     if viewController == cameraViewControllerInArray { 
      self.presentViewController(cameraViewControllerNotInArray, animated: true, completion: nil) 
      return false 
     } 
     return true 
     } 

Ich weiß nicht, ob es der beste Weg, um diesen Fehler zu erhalten ist, so lass es mich wissen. Vielen Dank für Ihre Antworten!

+1

Haben Sie versucht, den Camera Controller modal statt in einem Nav Controller anzuzeigen? Ich habe dies in einem ähnlichen Fall getan. –

+1

Wie @MikeTaverne sagt, sollte Ihre Kamera-Taste die Kamera-Ansicht moralisch über der Oberseite Ihres Tab-Bar-Controllers darstellen. Sie können einfach die Kamera cc entlassen und Sie werden genau dort zurück sein, wo Sie waren – Paulw11

+0

Haben Sie meine Antwort gelesen @Anjou –

Antwort

3

Sie können beim Anzeigen Ihres Kamerabildschirms einen anderen Ansatz wählen. Sie können dies modal präsentieren, was bedeutet, dass es von unten nach oben über die Tab-Leiste gleitet. Dies erreichen Sie in der Delegate-Methode shouldSelectViewController, die jedes Mal ausgeführt wird, wenn Sie den Index wechseln. Wenn es die Kamera dann präsentieren Sie Ihre VC aber zurückkehren NEIN, damit es nicht auf die Registerkarte Index ändern:

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { 
    if(viewController == cameraNavigationController) { 
     [self presentViewController:cameraNavigationController animated:YES completion:nil]; 
     return NO; 
    } 
    return YES; 
} 

können Sie dann auf die Schaltfläche zum Schließen erstellen, bevor Sie den View-Controller zurück in die Ansicht entlassen:

[self dismissViewControllerAnimated:YES completion:nil]; 
+0

Hallo, Entschuldigung für die Verspätung, ich stieß auf einige Issus, die versuchten, Ihre Lösung zu implementieren. Ich habe endlich einen Weg gefunden, aber ich bin mir nicht sicher, ob es der beste ist, könntest du den Edit in meiner Frage überprüfen? Danke für Ihre Antwort (markiert) – Anjou

1

Ich denke, dass Ihr konzeptionelles UI-Modell ist, was Sie das Problem verursacht. Wirklich, alle Registerkarten auf einem Tab-Controller sind normalerweise immer da. Wenn Sie auf eine Registerkarte klicken, wechseln Sie den Benutzer in eine Erfahrung mit Registerkarten.Der Benutzer möchte diese Erfahrung (gemäß den normalen Benutzeroberflächenverhalten) nicht wirklich verlassen, bis er auf eine andere Registerkarte klickt.

Aber Sie sagen effektiv zu dem Benutzer: "Klicken Sie auf den Kamera-Tab, um das Kameraerlebnis zu starten, und ich werde entscheiden, wohin Sie gehen werden, wenn Sie die Kameraerfahrung schließen." Dann sagen Sie in diesem Post: "Aber es fühlt sich unelegant an, wenn ich den Benutzer auf den gleichen Tab oder auf den Tab umleite, von wo aus Sie in die Kamera gekommen sind." Ich würde sagen, dass deine Sinne dir sagen, dass etwas nicht stimmt (und ich stimme ihnen zu).

Wenn Sie das Modell der Entscheidung, dass Benutzer nicht in der Kamera Erfahrung bleiben können, bis sie selbst ausschalten, implementieren, dann müssen Sie Ihre Emotionen mit diesem Modell glücklich machen. Und Sie müssen entscheiden, wohin sie gehen, wenn sie die Kamera schließen. Es gibt wirklich nur ein paar Möglichkeiten - gehen Sie immer auf einen Tab zurück (ugh); gehe zurück zu ihrem vorherigen Tab, behandle den Kamera-Tab als eine Modalerfahrung (inkonsistent mit dem gesamten Tab-Modell, aber besser als eine feste Rückkehr-Tab); oder um einen Punkt zu illustrieren, leite den Benutzer auf eine zufällige Registerkarte (double ugh) um.

Ich denke, wenn die Kamera Registerkarte wird sich wie ein Tab, muss es ein zweistufiger Prozess sein. Wechseln Sie zur Registerkarte "Kamera" und zeigen Sie dann auf der Registerkarte "Kamera" die Vollbildkamera modal an und kehren Sie zur Registerkarte "Kamera" zurück, wenn sie den gesamten Bildschirm schließen.

Ansonsten würde ich sagen, geben Sie auf der Registerkarte Controller, und legen Sie Tasten unten, so dass Sie die Kamera Erfahrung modal, Vollbild von einer Schaltfläche präsentieren können.

+0

Vielen Dank für die ausführliche Antwort. Ich stimme deinem Standpunkt zu, aber meine Idee war, etwas wie Instagram oder Vine UX neu zu erstellen. Wenn der Benutzer auf den Kamera-Tab klickt, nimmt der Bereich den gesamten Bildschirm mit einem "Zurück" - oder "Schließen" -Knopf auf. Ich werde über deine Idee nachdenken und sehen, was am besten für meine Anwendung passt, aber nur für den Fall, was denkst du über die Lösung von Benton und meine Art, es zu implementieren (du kannst es in EDIT 2 sehen) Danke nochmal – Anjou

+0

Ich denke dass Ihre Lösung ein kreativer Weg ist, um das Problem zu umgehen. :-) Aber natürlich liegt das Problem an deiner kreativen Nutzung der Tab-Leiste UI ... :-) Und anscheinend machen auch Instagram und Vine die gleiche Sache. Wann ist eine Tabulatortaste nicht eine Tabulatortaste? - Wenn es eine Kamera-Tab-Taste ist - und dann wirkt es wie eine Tesseract Tab-Taste! :-) – Kevin

Verwandte Themen