Adaptiver Übergang im Storyboard Xcode 6. Ist Push veraltet?

121

Der Xcode 6 Interface Builder verfügt standardmäßig über das neue Kontrollkästchen "Größenklassen verwenden". Es macht Ansichten anpassungsfähig. Geben Sie hier die Bildbeschreibung ein

Wenn ich versuche, zwischen zwei Ansichten in meinem Storyboard zu wechseln, habe ich neue Optionen: Geben Sie hier die Bildbeschreibung ein

stattdessen alt:

Geben Sie hier die Bildbeschreibung ein

Jetzt haben wir "zeigen" und "modal präsentieren" anstelle von "pushen" und "modal". Die alten Optionen werden als veraltet markiert. Ich habe die Option "show" gewählt, weil sie in den Segue-Einstellungen "show" (z. B. push) heißt.

Geben Sie hier die Bildbeschreibung ein

Aber es macht keinen Schub. Die Segue-Animation sieht aus wie eine Folie von unten (modal) und die Navigationsleiste verschwindet.

Die Frage ist: Wie kann ich "Show" wie Push funktionieren lassen? Ist es möglich oder sollte ich stattdessen "push (veraltet)" verwenden? Wo finde ich Informationen zu neuen Arten von Segues? Das einzige, was ich in der iOS8-Entwicklerbibliothek gefunden habe, sind Storyboards, die Ihnen beim Entwerfen Ihrer Benutzeroberfläche helfen, aber es gibt keine Informationen zu "show" segue.

AKTUALISIEREN

Ich habe versucht, ein neues Projekt zu erstellen und "show" funktioniert wirklich wie "push". Ich denke, das Problem in meinem Projekt kann sein, dass ich den Navigationscontroller mit diesem Code wiederverwenden kann, aber ich weiß nicht, wie ich ihn beheben soll.

if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
    SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
    
    swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
        
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    };
    
}

Danach versuche ich, NewViewController nach MainViewController zu pushen Geben Sie hier die Bildbeschreibung ein

UPDATE 2:

Ich scheine nur iOS 7, iOS 7.1 Problem zu sein.

John Kakon
quelle

Antworten:

97

Ja, verwenden Sie "Show" anstelle von "Push".

Wie kann ich "Show" wie Push funktionieren lassen? Ist es möglich oder sollte ich stattdessen "Push (Depricated)" verwenden?

Es sollte; es tut für mich. Ich verwende Xcode 6 Beta 2 und habe zum Testen die Einzelansichtsvorlage verwendet (Aufruf des vorgefertigten Ansichtscontrollers in IB 'VC_A'). Ich habe dann einen weiteren View Controller hinzugefügt ('VC_B'). Ich habe dann eine Schaltfläche auf VC_A hinzugefügt, um VC_B und eine andere von VC_B zurück zu VC_A anzuzeigen. Wenn ich im Storyboard einen Navigationscontroller als anfänglichen Ansichtscontroller hinzufüge und VC_A zum rootViewController mache, haben sowohl 'push' als auch 'show' den gleichen Effekt. Wenn ich keinen anfänglichen Navigationscontroller habe und 'show' verwende, erhalte ich das, was Sie darin beschrieben haben, dass der VC_B von unten nach oben rutscht. Wenn ich versuche zu "pushen", bekomme ich einen Absturz, da ich zum Schieben einen Navigationscontroller haben muss.

Wo finde ich Informationen zu neuen Arten von Segues?

Daher habe ich in der Sitzung "Was ist neu in Interface Builder?" Hier einige Informationen gefunden . Wenn Sie sich die Folien ansehen, sehen Sie eine Folie (41), die die Änderung erwähnt. Wenn Sie sich dieses Sitzungsvideo ansehen, können Sie zu Minute 38:00 springen, wo sie über adaptive Segmente sprechen. Sie erklären, dass der adaptive Abschnitt "Show" beispielsweise den Kontext berücksichtigt, wenn entschieden wird, wie die Präsentation eines neuen Ansichtscontrollers erfolgen soll.

Spencer Hall
quelle
Vielen Dank für Ihre Antwort. Ich habe versucht, ein neues Projekt zu erstellen und "show" funktioniert wirklich wie Push mit Navigations-Controller. In meinem Projekt habe ich eine komplizierte Struktur mit der Seitenleiste aus dieser Lektion appcoda.com/ios-programming-sidebar-navigation-menu und Push Works, Show nicht. Möglicherweise liegt der Grund darin, dass ich den Navigationscontroller wieder verwende. Ich habe meine Frage mit dem Wiederverwendungscode aktualisiert.
John Kakon
Das erste, was ich sehe, wenn ich mir Ihr Update ansehe, ist, dass Sie einen benutzerdefinierten Abschnitt erwarten: 'SWRevealViewControllerSegue'. Ja, es ist wahrscheinlich nicht sinnvoll, in Ihrem Fall 'show' oder 'push' zu verwenden, da diese integriert sind Segues, während Sie Ihren eigenen benutzerdefinierten Code ausführen möchten. Wenn ich das Beispielprojekt herunterlade, wird sogar die Auswahl von "Benutzerdefiniert" in den Abschnitten in der Storyboard-Datei angezeigt.
Spencer Hall
Ich habe diesen Abschnitt nicht gemeint. Ich habe darüber gesprochen, einen neuen UIViewController neben "MainViewController" zu erstellen (er verfügt über einen Navigationscontroller, und mein "Update" zeigt nur, wie ich ihn dort hin bekomme) und habe versucht, eine neue Ansicht in den MainViewController zu verschieben. Screenshot des Storyboards Ich bin Ihnen dankbar, wenn Sie im Beispielprojekt "Größenklassen verwenden" aktivieren, NewViewController erstellen und versuchen, mit "show" zwischen MainViewController und NewViewController zu wechseln. Sie werden sehen, wovon ich spreche.
John Kakon
Hab das gerade gemacht und zumindest für mich hat "Show" genauso funktioniert wie "Push".
Spencer Hall
9
Sie können den Fehler umgehen, indem Sie sicherstellen, dass auf allen Wegen in Ihren View Controller ein UINavigationController im Stammverzeichnis vorhanden ist. Selbst wenn dies bedeutet, dass Sie einen UINavigationController in Ihr Storyboard einfügen, auf den niemals zugegriffen werden kann. Es sieht so aus, als würde die Verkabelung verwendet, um auf das Verhalten zu schließen.
Scott Robertson
33

Es gibt bereits eine akzeptierte Antwort, aber ich wollte ein bisschen mehr Informationen geben, möglicherweise Informationen, die vorher nicht verfügbar waren.

Wie bereits erwähnt, waren die Segmente "Push" und "Modal" veraltet und wurden durch "Show" bzw. "Modal Present" ersetzt. Laut Apples Dokumentation wurden die neuen Segmente weiter in Segmente unterteilt, die sich an Größenklassen anpassen. Die älteren sollten nur zur Unterstützung von iOS-Versionen verwendet werden, die älter als iOS 8 sind.

Das Dokument im folgenden Link erklärt dies und die Beschreibung aller verfügbaren alten und neuen Segmente.

Hinzufügen eines Segues zwischen Szenen in einem Storyboard

Falls sich die URL in Zukunft ändert, ist dies die Erklärung für jeden neuen Abschnitt:

Show

Präsentieren Sie den Inhalt je nach Bildschirminhalt im Detail- oder Hauptbereich. Wenn die App eine Master- und Detailansicht anzeigt, wird der Inhalt in den Detailbereich verschoben. Wenn die App nur den Master oder das Detail anzeigt, wird der Inhalt auf den aktuellen View Controller-Stapel verschoben.

Detail anzeigen

Präsentieren Sie den Inhalt im Detailbereich. Wenn die App eine Master- und Detailansicht anzeigt, ersetzt der neue Inhalt das aktuelle Detail. Wenn in der App nur der Master oder das Detail angezeigt wird, ersetzt der Inhalt den oberen Rand des aktuellen View Controller-Stacks.

Modal präsentieren

Präsentieren Sie den Inhalt modal. Es gibt Optionen zur Auswahl eines Präsentationsstils (UIModalPresentationStyle) und eines Übergangsstils (UIModalTransitionStyle).

Als Popover präsentieren

Präsentieren Sie den Inhalt als Popover, das in einer vorhandenen Ansicht verankert ist. Es besteht die Möglichkeit, die möglichen Richtungen des Pfeils anzugeben, der an einer Kante der Popover-Ansicht angezeigt wird (UIPopoverArrowDirection). Es gibt auch eine Option zum Festlegen der Ankeransicht.

Alondono
quelle
24

tldr; Löschen Sie den Segue, der nicht richtig pusht, und erstellen Sie ihn im Storyboard neu, indem Sie ihn von einem UIView / UIControl auf den Zielansichts-Controller ziehen.

An den anderen Antworten ist nichts auszusetzen, aber hier wird erklärt, was passiert, wie Sie überprüfen können, ob es passiert, und wie Sie das Problem in Zukunft beheben können.

Hintergrund

In meinem Fall funktionierte keiner meiner Show Segues, obwohl ich bereits einen UINavigationController als anfänglichen Ansichtscontroller hatte (mit meinem Inhalt UIViewController als Root).

Warum und wie der Show-Segue bricht

Der Show-Segue wird unterbrochen, wenn eine Aktion mit dem Segue in der Quell-XML des Storyboards verknüpft ist. Ein typisches Szenario, das dies verursacht, könnte sein, wenn Sie einen Abschnitt von einem manuellen Abschnitt neu definiert haben, der zuvor im Code aufgerufen wurde. Dadurch bleiben die folgenden Bits in der Storyboard-XML.

<connections>
    <segue destination="85t-Z1-hxf" kind="show" identifier="ToOptions" action="showDetailViewController:sender:" id="gdZ-IX-KcN">
</connections>

Nota Bene Storyboard als XML anzeigen; Klicken Sie mit der rechten Maustaste auf die Storyboard-Datei und wählen Sie Öffnen als> Quellcode . Verwenden Sie zum Zurücksetzen Öffnen als> Interface Builder - Storyboard

Um benutzerdefinierte Aktionen bei Verwendung des Segues aus dem Storyboard zu berücksichtigen, können Sie einfach auf prepareForSegue tippen, den Controller für die Zielansicht abfangen und von diesem Speicherort aus beliebige Methoden aufrufen. In jedem Fall ist der Nebeneffekt für diesen kleinen Fehler (der Fehler ist die Tatsache, dass wenn Sie den Segue neu definieren, er nicht richtig in xml eingerichtet ist ~ dh die Aktion bleibt auch nach dem Ändern des Segues in einen, der von einem UIView (oder) aus ausgeführt wird, bestehen UIControl) an einen Target View Controller).

Leider schlägt die direkteste Lösung fehl. Wenn Sie also nur das XML-Attribut für die Aktion aus dem Storyboard entfernen, wird das Problem NICHT behoben. Stattdessen muss man einfach den Segue im Storyboard löschen und neu erstellen .

Nach der Neuerstellung hat die Storyboard-XML keine Aktion mehr, die dem jeweiligen Abschnitt zugeordnet ist, und die Show wird als Push ausgeführt.

Beispiel-XML für den korrekten Show Segue

  <connections>
    <segue destination="RbV-Au-WV9" kind="show" identifier="ToOptions" id="5dm-os-bcS"/>
  </connections>

Minderung

Um Wiederholungen zu vermeiden, müssen Sie sich nach Möglichkeit nur an nicht manuelle Storyboard-Abschnitte halten, indem Sie mit prepareForSegue die erforderlichen Aktionen basierend auf dem Zielansichts-Controller hinzufügen. Wenn Sie mischen und anpassen müssen, stellen Sie sicher, dass in Ihren Show-Segmenten keine Aktionen in der Storyboard-XML enthalten sind. Wenn Sie mit älteren Projekten arbeiten, sollten Sie dem Storyboard-Quellcode besondere Aufmerksamkeit widmen, da ich einige Probleme entdeckt habe.

Tommie C.
quelle
3
Nach Stunden hat mir das wahrscheinlich noch einige Stunden erspart. Folgendes würde ich basierend auf dem oben Gesagten vorschlagen: Öffnen Sie das Storyboard als Quellcode , suchen Sie nach kind = "show" und prüfen Sie , ob die Zeile so etwas wie action = "showDetailViewController: sender:" enthält . Wenn ja, löschen Sie alles aus action = bis zum Schließen " . Ich habe ein wirklich großes Storyboard und die betroffene Sequenz enthielt diesen Aktionsparameter nicht, aber eine andere nicht verwandte Zeile. Nachdem ich die Aktion gelöscht hatte, funktionierten alle adaptiven Sequenzen wieder wie erwartet. Nur das Löschen der betroffenen Sequenz funktionierte nicht." t Arbeit.
Marcus
Das hat mich auch gerettet.
Adam Bardon
1
Das Löschen des Aktionsattributs in XML funktionierte für meinen Freund.
Brent Royal-Gordon
hat mich auch gerettet
Jimmy George Thomas
Löschte das Aktionsattribut in der XML-Datei und voila, es funktioniert. Hätte das Problem ohne diesen Beitrag nie gefunden.
krizzzn
20

Wie Scott Robertson hier kommentierte , sieht dies wie ein Fehler in iOS 7 aus.

Es scheint, dass in iOS 8 der Übergang zur Laufzeit abgeleitet wird (korrektes Verhalten), während in iOS 7 der Übergang zur Entwurfszeit abgeleitet wird (fehlerhaftes Verhalten).

Die einfachste Problemumgehung besteht darin, dem Storyboard einen nicht verwendeten Navigationscontroller hinzuzufügen und ihn zu verknüpfen, sodass der betreffende Ansichtscontroller Teil dieses Navigationscontrollers ist. Sie müssen den Navigationscontroller nicht instanziieren, sondern nur den fehlerhaften Ansichtscontroller, um zu wissen, dass er in einen Navigationscontroller eingebettet ist.

Hinweis: Die Simulation einer Navigationsleiste reicht für diese Zwecke nicht aus. Sie müssen tatsächlich einen Navigationscontroller in seinem Push-Stack haben.

So reproduzieren Sie den Fehler:

  1. Erstellen Sie ein neues Storyboard, das Größenklassen verwendet.
  2. Erstellen Sie zwei Ansichts-Controller (keine Navigations-Controller).
  3. Lassen Sie den ersten Ansichts-Controller den zweiten Ansichts-Controller über eine Show anzeigen (z. B. Push). mit einer Schaltfläche verknüpften Übergang anzeigen.
  4. Zeigen Sie im Code den ersten Ansichts-Controller an, binden Sie ihn jedoch über die initWithRootViewController:Methode in einen Navigations-Controller ein .
  5. Führen Sie die App unter iOS 7 aus.
  6. Tippen Sie auf die Schaltfläche, die den Push ausführen soll.
  7. Unter iOS 7 erhalten Sie einen modalen Übergang anstelle eines Pushs. Unter iOS 8 erhalten Sie das richtige Push-Verhalten.

Geben Sie hier die Bildbeschreibung ein

So beheben Sie den Fehler:

  1. Fügen Sie dem Storyboard einen Navigations-Controller hinzu und legen Sie den ersten Ansichts-Controller als Root-Ansichts-Controller fest. (Hinweis: Durch Hinzufügen des zweiten als Root View Controller wird dieser Fehler NICHT behoben.)
  2. Geben Sie ihm eine Junk-ID, um die Warnung zu unterdrücken, dass auf den Navigationscontroller nicht zugegriffen werden kann, und um sich selbst zu dokumentieren, dass er nur als Problemumgehung vorhanden ist. (zB workaround for show segues in iOS 7).

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, wie der Navigationscontroller im zweiten Bild hinzugefügt wurde und keine eingehenden Pfeile enthält (dh es gibt keine andere Möglichkeit, ihn zu instanziieren, als seine View Controller-ID zu verwenden).

Sinnvoll
quelle
1
Danke, der Trick mit dem NavigationController hat es für mich getan, als ich den Root-Navigationscontroller-ViewController-Stack
Peter Pint
1
Beste Lösung. Danke
Илья Голованов
13

Ich weiß, dass ich zu spät komme, aber ich wollte mitteilen, was ich gelernt habe. Dies ist in der Tat ein Fehler und ist noch heute (18.12.2014) vorhanden.

Ich schrieb einen Artikel darüber hier .

Es ist leicht reproduzierbar; unter iOS8 funktioniert einwandfrei und sogar unter iOS7.x, solange Sie einen View Controller nicht programmgesteuert in den Stapel schieben, bevor Sie den ShowSegue aufrufen .

Wenn Sie nur über Storyboard-Verbindungen auf den Stapel pushen, funktioniert dies. aber anscheinend wenn man per code irgendwie das drücktnavigationController Eigenschaft des Puschs UIViewControllersein nilund wenn Sie es aufrufen Show, wird es ein Modal annehmen, weil es keine Navigation gibt, um den Stapel zu steuern.

Die einzige bisherige Problemumgehung besteht darin, entweder nicht per Code zu pushen (nicht durchführbar) oder die jetzt veraltete zu verwenden Push.

Ich habe ein Radar eingereicht (Link zum Artikel). Fühlen Sie sich frei, Duplikate einzureichen, in der Hoffnung, dass Apple dieses Problem behebt.

esttorhe
quelle
3
Das war genau mein Problem, danke! Die Verwendung von veraltetem Push scheint in diesem Fall die weniger böse Lösung zu sein.
Moshe Gottlieb
Eine weitere Problemumgehung besteht darin, dem Storyboard einen (nicht verwendeten) Navigationscontroller hinzuzufügen. Siehe stackoverflow.com/questions/24184003/…
Senseful
Nein! Es passiert hier und die Ursache ist kein programmatischer Schub. In meinem Fall Showführe ich einen Segue durch, dann wird der zweite ShowSegue modal dargestellt: Lösung?
Frade
@Frade kannst du auf ein Github-Repo verlinken, wo dies reproduzierbar ist? Laufen Sie auf welcher Version von iOS?
esttorhe
privates Projekt .. Es passiert, wenn versucht wird, einen (zweiten) ShowViewController unter iOS 7 auszuführen
Frade
2

Ich hatte das gleiche Problem mit Segues in Xcode 7 und iOS 7.1.2. Show Segues (neue Funktion von iOS 8) funktioniert wie modale Segues in iOS 7 und ermöglicht es Ihnen nicht, Ihre View Controller in den Navigationscontroller-Stack zu verschieben, wenn Sie den Segue-Typ mit Xcode in Ihrem Storyboard definieren. Aus diesem Grund gibt Ihr self.navigationController null zurück, da der View Controller nicht auf den Stapel verschoben wurde und Sie ihn nicht einfügen können.

Ich verstehe nicht, warum Apple in Xcode keine Benachrichtigungen für diesen Fall hinzugefügt hat, wenn Ihre App für iOS 7 erforderlich ist. Die Push-Methode ist veraltet, aber Show funktioniert mit iOS 7 nicht richtig.

Was habe ich getan, um das Problem zu beheben:

Ich habe die MYShowSegue-Klasse mit .h erstellt

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

Und .m-Datei mit nur einer Perform- Methode:

#import "MYShowSegue.h"

@implementation MYShowSegue

- (void) perform {

    if ([[[self sourceViewController] navigationController] respondsToSelector:@selector(showViewController:sender:)]) {

        id sender = nil;
        [[[self sourceViewController] navigationController] showViewController:[self destinationViewController] sender:sender];
    }else{

        [[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:YES];
    }
}

@end

Dann müssen Sie eine benutzerdefinierte festlegen für jeden Abschnitt in Ihrem Storyboard Typ und eine neue Klasse dafür auswählen, in meinem Fall war es MYShowSegue.

Beispiel für einen benutzerdefinierten Segue

Diese Lösung hilft Ihnen dabei, Ihre iOS 7-Apps vollständig zu unterstützen. Sie verwenden die pushViewController- Methode, um Ihre Ansichten zu pushen, und für iOS 8,9 usw. funktioniert Ihr Segue mit der neuen (iOS 8) -Methode showViewController

Vergessen Sie nicht, dasselbe mit all Ihren Abschnitten in Ihrem Storyboard zu tun.

Igor Tikhonov
quelle
Schöne Lösung - hat bei mir funktioniert (anstatt einen "unbenutzten" Navigationscontroller hinzuzufügen ...
Laurenz Glück
1

Dies geschieht immer noch in iOS 10.x.

Das Löschen und Wiederherstellen von Segues hat für mich nichts gelöst:

Problem: Erforderliche Funktionalität waren 7 Segmente, die nur als "Push" (eigentlich ein Show-Detail) fungieren, aber tatsächlich würde nur das erste Segment, das ich hinzugefügt habe, pushen, die anderen würden sich alle modal verhalten. Dies geschieht, obwohl der Interface Builder die einzelnen Segmente identisch beschreibt.

Lösung: Ich musste die Aktion zu den 6 Abschnitten hinzufügen, die sie nicht hatten.

Original Storyboard XML

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" id="3NK-93-wTy"/>
</connections>

Ich habe dies geändert, indem ich showViewController: sender hinzugefügt habe

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" action="showViewController:sender:" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" action="showViewController:sender:" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" action="showViewController:sender:" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" action="showViewController:sender:" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" action="showViewController:sender:" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" action="showViewController:sender:" id="3NK-93-wTy"/>
</connections>
Damo
quelle