"From View Controller" verschwindet mit UIViewControllerContextTransitioning


105

Ich habe ein Problem und habe es unten beschrieben.

Ich verwende UIViewControllerContextTransitioningfür benutzerdefinierte Übergänge.

Ich habe 2 View Controller, First View Controller und Second View Controller.

Jetzt möchte ich den zweiten Ansichts-Controller mit einer Animation zum ersten Ansichts-Controller hinzufügen. Ich habe es erreicht, jetzt ist der zweite Ansichts-Controller transparent, so dass wir den ersten Ansichts-Controller unter dem zweiten Ansichts-Controller sehen können.

Aber ich kann den Controller für die erste Ansicht nicht sehen, und ich kann nur einen schwarzen Bildschirm unter dem Controller für die zweite Ansicht sehen.

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    self.transitionContext = transitionContext;
    if(self.isPresenting){
        [self executePresentationAnimation:transitionContext];
    }
    else{
       [self executeDismissalAnimation:transitionContext];
    }
  }

-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
     UIView* inView = [transitionContext containerView];
     UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

     UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

     CGRect offScreenFrame = inView.frame;
     offScreenFrame.origin.y = inView.frame.size.height;
     toViewController.view.frame = offScreenFrame;

    toViewController.view.backgroundColor = [UIColor clearColor];
    fromViewController.view.backgroundColor = [UIColor clearColor];
    inView.backgroundColor = [UIColor  clearColor];
    [inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
     // [inView addSubview:toViewController.view];
    CFTimeInterval duration = self.presentationDuration;
    CFTimeInterval halfDuration = duration/2;

    CATransform3D t1 = [self firstTransform];
    CATransform3D t2 = [self secondTransformWithView:fromViewController.view];

    [UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{

    [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t1;
    }];

    [UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t2;
    }];
    } completion:^(BOOL finished) {
    }];


    [UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
        toViewController.view.frame = inView.frame;
    } completion:^(BOOL finished) {
        [self.transitionContext completeTransition:YES];
    }];
}

Beim [self.transitionContext completeTransition:YES];Aufruf verschwindet plötzlich der erste Ansichts-Controller und unter dem zweiten Ansichts-Controller wird ein schwarzer Bildschirm angezeigt.

Hat jemand eine Idee? Vielen Dank.

Antworten:


98

Ich hatte hier das gleiche Problem - sieht aus wie ein Fehler in iOS 8. Ich habe ein Radar eingereicht .

Ich habe Reveal verwendet , um die Ansichtshierarchie zu überprüfen, nachdem der Bildschirm schwarz geworden ist. Der Schlüssel UIWindowist komplett leer - überhaupt keine Ansichtshierarchie!

Enthüllt

Ich habe ein bisschen herumgespielt und es sieht so aus, als gäbe es eine einfache Problemumgehung für einfache Fälle. Sie können die toViewControllerAnsicht des Schlüssels einfach als Unteransicht des Schlüsselfensters erneut hinzufügen :

transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)

Ich habe es überprüft und das Schlüsselfenster rootViewControllerist immer noch richtig eingestellt, also ist das in Ordnung. Ich bin mir nicht sicher, was passieren würde, wenn Sie Ihren Controller in einem bereits vorgestellten modalen Controller präsentieren würden. In komplexeren Fällen müssen Sie also experimentieren.


2
Ich habe auch dieses Problem gesehen. iOS 8 führt eine neue Methode und Schlüssel für den Zugriff auf fromView und toView ein (Hinweis: kein View-Controller). Es scheint, als ob diese Referenzen während des Übergangs nicht verloren gehen. Sie können sie wie gewohnt zur Containeransicht hinzufügen, wenn Sie sie gerade von den Ansichtscontrollern abgerufen haben.
Tapi

1
Ich habe eine ähnliche Verrücktheit bei iOS 8 festgestellt, als ich versucht habe, der Ansicht meines Navigationscontrollers in viewDidLoad Unteransichten hinzuzufügen. Das erneute Hinzufügen der Ansicht des Navigationscontrollers zum keyWindow schien den Trick zu tun, vielen Dank, Ash!
Taber

1
Ich sehe das immer noch in GM (und dieses Update funktioniert immer noch). Sehen andere dasselbe? Ist dies nur eine Änderung in der API?
rjkaplan

21
Ich habe festgestellt, dass dieser Fehler (und viele mehr!) Verschwindet, wenn Sie ihn einstellen modalPresentationStyle = UIModalPresentationFullScreen. Sie erhalten natürlich immer noch Ihre benutzerdefinierte Übergangsanimation.
Chris

1
Danke @AshFurrow. Schöne Problemumgehung, bis es behoben ist!
kandelvijaya

78

Ich denke, die Gründe dafür sollten besser erklärt werden.

Die Ansicht verschwindet, weil Sie die Ansicht des präsentierenden Ansichts-Controllers aus ihrer ursprünglichen Position (Ansichtshierarchie) herausnehmen, sie in die von Ihrem Animator bereitgestellte containerView einfügen, sie aber nach Abschluss der Animation nie wieder zurückgeben. Damit wird die Ansicht des View Controllers mit seiner Superview (containerView) vollständig aus dem Fenster entfernt.

In iOS 7 hat das System die Ansichten der View Controller, die an der Präsentation beteiligt sind (Präsentieren und Präsentieren), immer an ihre ursprünglichen Stellen zurückgesetzt, nachdem der Übergang automatisch abgeschlossen wurde. Dies ist bei einigen Präsentationsstilen in iOS 8 nicht mehr der Fall.

Die Regel ist sehr einfach: Der Animator sollte die Ansicht des präsentierenden Ansichtscontrollers nur bearbeiten, wenn die Ansicht dieses Ansichtscontrollers bis zum Ende des Übergangs vollständig ausgeblendet (aus der Ansichtshierarchie entfernt) wird . Mit anderen Worten bedeutet dies, dass nach Abschluss der anfänglichen Präsentationsanimation nur die Ansicht des präsentierten Ansichtscontrollers sichtbar ist und nicht die Ansicht des präsentierenden Ansichtscontrollers. Wenn Sie beispielsweise die Deckkraft der Ansicht des dargestellten Ansichtscontrollers auf 50% setzen und UIModalPresentationFullScreen verwenden, wird die Ansicht des dargestellten Ansichtscontrollers unter dem dargestellten nicht angezeigt. Wenn Sie jedoch UIModalPresentationOverFullscreen verwenden, werden Sie dies tun (die shouldRemovePresentersViewMethode von UIPresentationController ist dafür verantwortlich, dies anzugeben).

Lassen Sie den Animator die Ansicht des Controllers für die präsentierende Ansicht jederzeit bearbeiten. Wenn die Ansicht des Controllers für die Präsentationsansicht nach Abschluss der Animation während des gesamten Präsentationslebenszyklus sichtbar bleibt, muss sie zunächst überhaupt nicht animiert werden - sie bleibt einfach dort, wo sie ist. Zweitens, wenn der Besitz für diesen Ansichtscontroller auf den Präsentationscontroller übertragen wird, weiß der Präsentationscontroller höchstwahrscheinlich nicht, wie die Ansicht dieses Ansichtscontrollers bei Bedarf zu gestalten ist, beispielsweise wenn sich die Ausrichtung ändert, aber der ursprüngliche Eigentümer des Präsentationsansichtscontrollers tut dies .

In iOS 8 wurde die viewForKey:Methode eingeführt, um Ansichten abzurufen, die der Animator bearbeitet. Erstens ist es hilfreich, die oben beschriebene Regel zu befolgen, indem Sie nil zurückgeben, wenn der Animator die Ansicht nicht berühren sollte. Zweitens wird möglicherweise eine andere Ansicht zurückgegeben, die der Animator animieren kann. Stellen Sie sich vor, Sie implementieren eine Präsentation ähnlich dem Formularblatt. In diesem Fall möchten Sie der Ansicht des dargestellten Ansichts-Controllers Schatten oder Dekoration hinzufügen. Der Animator animiert stattdessen diese Dekoration und die Ansicht des dargestellten Ansichts-Controllers ist ein Kind der Dekoration.

viewControllerForKey: geht nicht weg, kann trotzdem verwendet werden, wenn ein direkter Zugriff auf Ansichts-Controller erforderlich ist, der Animator jedoch keine Annahmen über die Ansichten treffen sollte, die zum Animieren benötigt werden.

Es gibt verschiedene Möglichkeiten, um ein Problem mit der Ansicht eines verschwindenden darstellenden Ansichtscontrollers zu beheben, wenn Sie sie explizit in die Containeransicht des Animators einfügen:

  1. Wenn Sie die Ansicht des präsentierenden Ansichtscontrollers nicht animieren müssen, verwenden Sie diese Option viewForKey:, um Ansichten zum Animieren zu bringen, anstatt direkt die Ansichten des Controllers anzuzeigen. viewForKey:kann keine oder sogar völlig andere Ansichten zurückgeben.

  2. Wenn Sie die Ansicht der Controller der präsentierenden Ansicht animieren möchten, sollten Sie die Verwendung des UIModalPresentationFullScreenStils in Betracht ziehen oder weiterhin UIModalPresentationCustomIhre eigene Unterklasse von UIPresentationController verwenden und implementieren, wenn Sie shouldRemovePresentersViewzurückkehren YES. Tatsächlich ist die Implementierung dieser Methode der Hauptunterschied zwischen internen Präsentationscontrollern UIModalPresentationFullScreenund UIModalPresentationCustomStilen, abgesehen von der Tatsache, dass Sie mit letzteren benutzerdefinierte Präsentationscontroller verwenden können.

  3. In allen anderen seltenen Fällen müssen Sie die Ansicht des Controllers für die präsentierende Ansicht an den ursprünglichen Speicherort zurücksetzen, wie in anderen Antworten vorgeschlagen.


2
Das ist super seltsam, weil dieser Code nur dann auf viewControllerForKey:s basiert, viewwenn viewForKey:nil zurückgegeben wird, und ich ihn trotzdem manuell zum Fenster hinzufügen musste. Haben Sie ein Beispiel für Code, der ohne diese Problemumgehung funktioniert?
Ash Furrow

Wenn viewForKey:null zurückgegeben wird, müssen Sie die Ansicht des präsentierenden Ansichts-Controllers mit Sicherheit erneut zum Fenster hinzufügen, wenn Sie sie in Ihrem Animator daraus entfernen. Wenn viewForKey die Ansicht des tatsächlichen Ansichtscontrollers zurückgibt, kann diese Ansicht sicher verschoben werden, da UIKit sie nach Ablauf des Präsentationslebenszyklus wieder an ihre ursprüngliche Position verschieben würde.
egdmitry

Vielen Dank, dass Sie die Gründe für dieses Problem erläutert haben. Du hast absolut recht. Wenn Sie die Position der Ansicht in der Ansichtshierarchie verschieben, ohne sie zu ersetzen, wird sie offensichtlich ausgeblendet (nach iOS 8, und ich arbeite gerade mit iOS 10!). Vielen Dank für Ihre Klarstellung.
Clay Ellis

1
Vielen Dank an egdmitry für Ihre Klarstellung. Was wirft eine andere Frage auf: Wie sollte ich Ihrer Meinung nach eine Präsentation wie eine Enthüllung implementieren ? Eine der heutzutage sehr verbreiteten Situationen, in denen die Präsentationsansicht teilweise herausgleitet, um die präsentierte Ansicht darunter anzuzeigen? In diesem Szenario müssen sowohl die präsentierende als auch die präsentierte Ansicht auf dem Bildschirm angezeigt werden, und die präsentierende Ansicht ist die animierte.
Andrea

70

In iOS 8 müssen Sie die von zurückgegebenen Ansichten viewForKey:anstelle der .viewEigenschaft der von zurückgegebenen Ansichtscontroller bearbeiten viewControllerForKey:. Dies geht aus der Beta-Dokumentation nicht besonders hervor. Wenn Sie sich jedoch die Quelle für UIViewControllerTransitioning.h ansehen, sehen Sie diesen Kommentar oben viewControllerForKey::

// Currently only two keys are defined by the
// system - UITransitionContextToViewControllerKey, and
// UITransitionContextFromViewControllerKey.
// Animators should not directly manipulate a view controller's views and should
// use viewForKey: to get views instead.
- (UIViewController *)viewControllerForKey:(NSString *)key;

toViewController.viewVerwenden Sie also den Rückgabewert von , anstatt Frames usw. von anzupassen [transitionContext viewForKey:UITransitionContextToViewKey].

Wenn Ihre App iOS7 und / oder Xcode 5 unterstützen muss, können Sie in UIViewController eine einfache Kategoriemethode wie die folgende verwenden:

- (UIView *)viewForTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        NSString *key = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey] == self ? UITransitionContextFromViewKey : UITransitionContextToViewKey;
        return [transitionContext viewForKey:key];
    } else {
        return self.view;
    }
#else
    return self.view;
#endif
}

Dann holen Sie sich Ihre toViewControllerund fromViewControllerwie gewohnt, aber holen Sie sich die Ansichten mit [toViewController viewForTransitionContext:transitionContext].

Bearbeiten: Es scheint einen Fehler zu geben, bei dem die Ansicht des Controllers für die Präsentationsansicht bei der Rückkehr von Null ist viewForKey, wodurch Sie keine modalen Übergänge vornehmen können, die die Präsentationsansicht überhaupt animieren (z. B. Abrutschen oder horizontales Umdrehen). Ich habe einen Fehler für iOS8 unter rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ) eingereicht . Siehe auch das Beispielprojekt unter http://github.com/bcherry/TransitionBug

Bearbeiten 2: Dank Graveley für den Vorschlag wird das Problem durch die Verwendung von UIModalPresentationFullScreen behoben. Vielleicht ist das kein Fehler. Apple beabsichtigt möglicherweise, dass UIModalPresentationCustom nur die Ansicht des eingehenden Modals ändert. Wenn Sie die ausgehende Ansicht ändern möchten, müssen Sie die Vollbilddarstellung der neuen Ansicht gewährleisten. In jedem Fall sollten Sie viewForKeyUIModalPresentationFullScreen verwenden.


2
Der viewForKey-Fehler hat mich verrückt gemacht! - Danke für die Einreichung. FWIW mein Übergang funktioniert einwandfrei, indem die Ansicht von UITransitionContextToViewControllerKey abgerufen wird, aber mein Übergang wendet nur eine Transformation auf die gesamte Ansicht an. Ich bin nicht sicher, ob das als manipulatingdie Ansichten des VCs interpretiert werden sollte oder nicht ...
MathewS

1
Wow - das ist verrückt. Ich habe das in den Unterschieden nicht gesehen - wahrscheinlich, weil es nur ein kleiner Kommentar ist. Wirklich frustrierend, wenn Apple so einen Stunt macht. Daumen drücken über dein Radar.
Ash Furrow

Ich sehe den viewForKeyFehler auch im GM. Sind es auch andere? Haben Sie eine vernünftige Problemumgehung dafür gefunden?
rjkaplan

2
Ich dachte laut Kommentar von - viewForKey// viewForKey: kann nil zurückgeben, was darauf hinweisen würde, dass der Animator die Ansicht des zugehörigen View Controllers nicht manipulieren sollte. Zurück nilist kein Fehler.
Ken Kuan

4
@kenKuan Sie könnten Recht haben. Gibt bei Verwendung von UIModalPresentationFullScreen viewForKeydie Ansicht von und die Ansicht von zurück. Vielleicht ist es beabsichtigt, dass für UIModalPresentationCustom Null zurückgegeben wird. Ich aktualisiere meinen Fehlerbericht und werde ihn hier veröffentlichen, wenn ich von Apple etwas darüber höre.
Bcherry

24

modalPresentationStyleWenn ich nicht auf UIModalPresentationCustom eingestellt habe, wurde das Problem für mich behoben.

Mit anderen Worten: Wenn Sie die Standardeinstellung von UIModalPresentationFullScreen beibehalten, anstatt UIModalPresentationCustom anzugeben, wurde das Problem mit der verschwindenden Ansicht behoben. Beachten Sie, dass das UIViewControllerTransitioningDelegate-Protokoll auch dann noch eingehalten wird, wenn es auf der Standardeinstellung belassen wird. Wenn ich mich richtig erinnere, war UIModalPresentationCustom einmal eine Anforderung.

Funktioniert bisher, habe dies nur für nicht interaktive Animationen versucht.


1
Beeindruckend. Das hat es geschafft! Ich habe ohne modalPresentationStyle in iOS7 & 8 getestet und es funktioniert in beiden. Vielen Dank!!
Ah Ryun Moon

1
Danke dir! Dies kombiniert mit der Verwendung viewForKey:anstelle .viewder viewControllerForKey:Korrekturen behebt alle Probleme für mich.
Bcherry

1
Dies hat das Problem für mich behoben, ohne viewForKey zu verwenden, aber ich nehme an, dass dies auch verwendet werden sollte.
Kevin Sliech

5
Obwohl dies das Problem zu beheben scheint, ist es wichtig zu beachten, dass der Bildschirm hinter Ihrem View Controller schwarz wird, sobald er angezeigt wird. Dies ist wichtig, wenn Ihr View Controller nicht im Vollbildmodus angezeigt wird.
Der Typ

16

Ich habe diese äußerst nützliche Antwort in einem verwandten Thread von Lefteris gefunden: https://stackoverflow.com/a/27165723/3709173

Etwas zusammenfassen:

  1. Setzen Sie modalPresentationStyle auf .Custom
  2. Unterklasse UIPresentationController, überschreiben sollteRemovePresentersView (mit NO)
  3. Überschreiben Sie den PresentationControllerForPresentedViewController in Ihrer TransitionDelegate-Klasse und geben Sie Ihren benutzerdefinierten UIPresentationController zurück

+1 in Ihrem benutzerdefinierten Übergang, fügen Sie toView nicht hinzu, wenn die Entlassungsanimation ausgeführt wird.

Hier demonstriert:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 ohne Hacks! Es ist wie Magie! :) :)


1
Dies ist die richtige Antwort. Ohne Zaubertricks wie im akzeptierten. Danke, Mark!
Andrei Malygin

Leider funktioniert dies in iOS 12.4, Xcode 10.3 nicht. Der Bildschirm wird nach Abschluss des Übergangs schwarz (alle Ansichten wurden aus der Hierarchie entfernt. Wenn Sie jedoch die Eigenschaft 'modalPresentationStyle' auf '.fullscreen' setzen, funktioniert dies. Prost.
Womble

Ich habe die Obj-C-Version von Mark und Gwinyais Swift-Implementierung in meinem Projekt ausprobiert. Leider funktioniert keiner von ihnen wie erwartet. Ich verwende Xcode 11.1 und das Build-Ziel ist iOS 13.0. Ich habe es sowohl auf dem Gerät als auch auf dem Simulator versucht. In meinem Fall ist meine Grundeinstellung eine Sammlungsansicht. Wenn Sie auf eine Zelle tippen, wird eine Detailansicht mit Animation angezeigt. Es funktioniert jedoch völlig einwandfrei, wenn ich die Standardübergangsanimation verwende. Die präsentierende VC wird nicht verschwunden sein, wenn ich aus den Details die Ansicht wieder aufnehme.
infinity_coding7

8

In iOS 8 müssen Sie einen UIPresentationController erstellen und die folgende Methode im UIViewControllerTransitioningDelegate implementieren.

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

Bittet Ihren Delegierten, den benutzerdefinierten Präsentationscontroller zum Verwalten der Ansichtshierarchie beim Präsentieren eines Ansichtscontrollers zu verwenden.

Rückgabewert:

Der benutzerdefinierte Präsentationscontroller zum Verwalten der modalen Präsentation.

Diskussion:

Wenn Sie einen Ansichtscontroller mit dem Präsentationsstil UIModalPresentationCustom präsentieren, ruft das System diese Methode auf und fragt nach dem Präsentationscontroller, der Ihren benutzerdefinierten Stil verwaltet. Wenn Sie diese Methode implementieren, erstellen Sie damit das benutzerdefinierte Präsentationscontrollerobjekt, das Sie zum Verwalten des Präsentationsprozesses verwenden möchten, und geben es zurück.

Wenn Sie diese Methode nicht implementieren oder wenn Ihre Implementierung dieser Methode null zurückgibt, verwendet das System ein Standardobjekt für den Präsentationscontroller. Der Standard-Präsentations-Controller fügt der Ansichtshierarchie keine Ansichten oder Inhalte hinzu.

Verfügbarkeit Verfügbar in iOS 8.0 und höher.

Weitere Informationen finden Sie im WWDC 2014-Video:

https://developer.apple.com/videos/wwdc/2014/?include=228

Es gibt auch einen Beispielcode aus dem WWDC mit dem Namen "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects", den Sie von der WWDC 2014-Beispielcodepage herunterladen können.

Möglicherweise müssen Sie den Beispielcode ein wenig ändern. Die UIPresentationController-Init-Methode wurde geändert in:

initWithPresentedViewController:presented presentingViewController:presenting

Bevor es präsentiert und dann präsentiert wurde. Tauschen Sie sie einfach aus und es sollte funktionieren.


Es tut uns leid, dass Sie das verknüpfte Video nicht angesehen haben, aber ich glaube nicht, dass Sie einen benutzerdefinierten UIPresentationController benötigen, es sei denn, Sie möchten nach Abschluss der Animation eine nicht standardmäßige Präsentation wie eine kreisförmige präsentierte Ansicht. Wenn Sie nur eine andere Animation wünschen, sollte die Implementierung von UIViewControllerAnimatedTransitioning aufgrund meines begrenzten Wissens ausreichen.
Vaddadi Kartick

7

anstelle von [inView insertSubview: toViewController.view obenSubview: fromViewController.view]; füge einfach hinzu: [inView addSubview: toViewController.view];

if (self.presenting) {

    [transitionContext.containerView addSubview:toViewController.view];
    // your code

} else {
    // your code
}

Hier sehen Sie ein Beispiel: link und es funktioniert unter iOS 7 und iOS 8


Dies sollte die akzeptierte Antwort für die Ausführung einer Animation vom Typ UIModalPresentationStyleCustom sein, da der fromViewController nicht zur containerView hinzugefügt werden muss. Sie müssen den toViewController nur während der präsentierenden Animation hinzufügen.
Scott Kaiser

Dies ist eigentlich sehr hilfreich
Dmitry Bondarev

7

Hier ist eine Objective C-Version von Ashs Fix.

// my attempt at obj-c version of Ash's fix
UIView *theToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
[[[UIApplication sharedApplication] keyWindow] addSubview:theToView];
[transitionContext completeTransition:YES]

Ich musste die Reihenfolge austauschen und die Methode [TransitionContext completeTransition:] aufrufen, nachdem ich die Ansicht wieder hinzugefügt hatte, um einen neuen Ansichts-Controller aus dem Block zum Schließen der Entlassung eines anderen Ansichts-Controllers zu präsentieren, damit er richtig funktioniert.

Ich weiß nicht, dass dies das Problem für alle beheben wird, aber es funktioniert in meiner App. Prost!


5

Ich fand, dass dies für Obj-C gut funktioniert hat:

    [transitionContext completeTransition:YES];
    if(![[UIApplication sharedApplication].keyWindow.subviews containsObject:toViewController.view]) {
        [[UIApplication sharedApplication].keyWindow addSubview:toViewController.view];
    }

Scheint sowohl auf ios7 als auch auf ios8 gut zu funktionieren.


5

Ich habe festgestellt, dass viewForKey:UITransitionContextToViewKeyauf ios8 null zurückgegeben wird. Wenn es also Null ist, greife ich auf die Ansicht vom 'to'-View-Controller zu.

Dies scheint jedoch dazu zu führen, dass die 'to'-Ansicht beim completeTransition:YESAufruf nicht vom Container in das Fenster verschoben wird. Wenn also viewForKey:UITransitionContextToViewKeynull zurückgegeben wird, falle ich zu null toVC.viewund verfolge die Tatsache, dass es null zurückgegeben hat. Nach Abschluss verschiebe ich es in die anfängliche Übersicht des Containers (die zufällig das Fenster ist).

Dieser Code funktioniert also sowohl unter iOS7 als auch unter iOS8 und sollte auch unter iOS9 funktionieren, selbst wenn sie ihn beheben oder nicht.

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    // Get the 'from' and 'to' views/controllers.
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    BOOL hasViewForKey = [transitionContext respondsToSelector:@selector(viewForKey:)]; // viewForKey is iOS8+.
    UIView *fromView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextFromViewKey] :
        fromVC.view;
    UIView *toView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextToViewKey] :
        toVC.view;

    // iOS8 has a bug where viewForKey:to is nil: http://stackoverflow.com/a/24589312/59198
    // The workaround is: A) get the 'toView' from 'toVC'; B) manually add the 'toView' to the container's
    // superview (eg the root window) after the completeTransition call.
    BOOL toViewNilBug = !toView;
    if (!toView) { // Workaround by getting it from the view.
        toView = toVC.view;
    }
    UIView *container = [transitionContext containerView];
    UIView *containerSuper = container.superview; // Used for the iOS8 bug workaround.

    // Perform the transition.
    toView.frame = container.bounds;
    [container insertSubview:toView belowSubview:fromView];
    [UIView animateWithDuration:kDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
        fromView.frame = CGRectOffset(container.bounds, 0, CGRectGetHeight(container.bounds));
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];

        if (toViewNilBug) {
            [containerSuper addSubview:toView];
        }
    }];
}

3

Ich habe festgestellt, dass dieser Fehler (und viele mehr!) Verschwindet, wenn Sie ihn einstellen modalPresentationStyle = UIModalPresentationFullScreen. Sie erhalten natürlich immer noch Ihre benutzerdefinierte Übergangsanimation.


2

Ich habe mich auch mit diesem Thema beschäftigt. Ich wollte einen benutzerdefinierten Übergang mit einem halbtransparenten Hintergrund erstellen, in dem ich immer noch den Ansichts-Controller sehen konnte, von dem ich kam, aber nur einen schwarzen Hintergrund. Ich fand, dass Mark Arons Antwort in diesem Thread mir geholfen hat, aber sie ist in Ziel C geschrieben. Hier ist eine Swift 3-Version dieser Antwort, die ich für iOS 9 und iOS 10 getestet habe:

  1. Erstellen Sie eine Unterklasse von UIPresentationController. Überschreiben Sie die shouldRemovePresentersView wie folgt auf false:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. Geben Sie an der Stelle, an der Sie den neuen Ansichtscontroller instanziieren und seinen Übergangsdelegierten festlegen, an, dass er einen benutzerdefinierten modalen Präsentationsstil wie folgt anzeigen soll:

    let newVC = mainStoryboard.instantiateViewController(withIdentifier: "newVC") as! NewViewController 
    
    newVC.transitioningDelegate = self
    
    newVC.modalPresentationStyle = UIModalPresentationStyle.custom
    
    newVC.modalPresentationCapturesStatusBarAppearance = true //optional
    
    present(newVC, animated: true, completion: nil)
  3. Überschreiben Sie nun die PresentationController-Methode Ihres UIViewControllerTransitioningDelegate und geben Sie Ihren benutzerdefinierten UIPresentationController zurück. Ich hatte meine als Erweiterung meiner aktuellen Klasse:

    extension CurrentViewController: UIViewControllerTransitioningDelegate {
    
    //this is where you implement animationController(forPresented) and animationController(forDismissed) methods
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    
    return ModalPresentationController(presentedViewController: presented, presenting: source)
    
    }
    }

Eine andere Sache, die Sie beachten sollten, ist, dass Sie nicht versuchen sollten, Ihre fromView in Ihrer presentAnimator-Klasse zu referenzieren. Dies ist Null und Sie erhalten zur Laufzeit einen Fehler. Anders als das, wenn Sie Dinge wie Dinge implementieren, erhalten Sie Ihren benutzerdefinierten Übergang mit seiner Animation und einem halbtransparenten Hintergrund, wenn Sie einen erstellen.


Dies ist ein großartiges Beispiel für eine benutzerdefinierte modale Präsentation in Swift 3! Danke @gwinyai! Ich blieb super presentationController(forPresented presented UIViewController,... hängen, bis ich ein Beispiel fand, das die neue Swift 3-API zeigte, weil die vorherige Swift-API den Complier nicht verärgerte, aber nicht aufgerufen wurde.
Natalia

2

Nachdem ich auf dieses Problem gestoßen war, war ich sehr verwirrt, weil ich vor nicht allzu langer Zeit etwas fast Identisches geschrieben hatte, das gut funktionierte. Kam hierher und suchte nach Antworten, um Korrekturen zu finden, die ziemlich hackig aussehen und die Grundursache nicht zu verstehen scheinen ... es ist eigentlich sehr einfach zu beheben.

Einige Antworten erwähnen den Wechsel modalPresentationStylezu .overFullScreen. Das ist richtig, .overCurrentContextwürde auch funktionieren. Dies wird erwartet und das Verhalten von Apple dokumentiert. Aber warum funktioniert das nicht für alle? Warum all der hackige Code und Kombinationen davon mit etwas anderem und verrückten Sachen, die du nicht machen solltest?

Es stellt sich heraus, dass Sie den Präsentationsstil VOR DEN VIEW-LADUNGEN festlegen müssen . Nicht danach. Führen Sie dies in init oder vom vorherigen Controller aus oder wie Sie möchten - solange die Ansicht geladen wird.


1
Ich habe den Präsentationsstil auf .overCurrentContext vor dem Laden der Ansicht (im initAnsichts-Controller) eingestellt und das Problem tritt immer noch auf
Ricardopereira

1

Die Verwendung des neuen UIModalPresentationOverCurrentContext hat dies für mich behoben. Mein ursprünglicher Übergang unter iOS 7 bestand darin, einen unscharfen Hintergrund der Ansicht unter dem Modal zu haben.


Aus irgendeinem Grund scheint dies keine Interaktion mit der Ansicht darunter zu ermöglichen, wie es UIModalPresentationCurrentContext in iOS 7 getan hat. Irgendwelche Gedanken?
Christopher Wirt

Hmm für mich unter iOS 10 führt .overCurrentContext zu diesem Fehler, .fullscreen jedoch nicht. Ich bin hierher gekommen, um auf eine Lösung für die Verwendung von .overCurrentContext zu hoffen, aber bisher scheint nichts unter iOS 10 zu funktionieren, außer vielleicht UIPresentationController zu unterordnen ...
Natalia

0

Ok, Leute, ich denke, ich löse einen Fall, in dem 'ein funktionierender Animator' nicht mehr richtig funktioniert, wenn Sie eine App in iOS 13 und höher erstellen.

Env Xcode 11.1, iOS 13.1

Problem

Was ich tun möchte, ist sehr einfach: Ich habe eine Sammlungsansicht. Wenn auf eine Zelle getippt wird, wechselt sie zu einer Detailansicht. Anstatt den langweiligen Standardstil "Modal präsentieren" zu verwenden, möchte ich ihn interessanter gestalten. Deshalb habe ich einen Animator für den Übergang zum View Controller geschrieben.

Ich habe den Übergang in IB per Drag & Drop von meiner Sammlungs-VC zur Detail-VC eingerichtet. Der Stil des Segues ist "Modal präsentieren" und die Präsentation ist auf "Vollbild" eingestellt.

Wenn die Detailansicht angezeigt wird, funktioniert alles wie erwartet. Wenn ich jedoch die Detailansicht verwerfe und zur Sammlungsansicht zurückkehre, kann ich nur die animierte Detailansicht sehen. Die Sammlungsansicht ist einfach verschwunden. Ich stocherte hier und da und habe ein paar Entdeckungen

1. Gleich nachdem die folgende Zeile von der Funktion 'animateTransition ()' aufgerufen wurde, wird die Sammlungsansicht fortgesetzt und angezeigt

transitionContext.completeTransition(true)

2. Solange die Detailansicht die Sammlungsansicht nicht vollständig abdeckt, verschwindet die Sammlungsansicht nicht, wenn sie von der Detailansicht zurückkehrt

Lösung

Um ehrlich zu sein, weiß ich wenig darüber, wie der animierte Übergang funktioniert. Ich kann also nur diesem und dem anderen Beitrag folgen und jede der Antworten ausprobieren. Leider funktioniert keiner von ihnen für mich. Schließlich kam ich zu einem Punkt, an dem ich nur noch den Präsentationsstil von Segue in IB optimieren kann (was ich ganz am Anfang hätte tun sollen). Wenn ich die Präsentation auf "Über Vollbild" setze, geschieht ein Wunder und mein Problem ist gelöst. Die Detailansicht kann im Vollbildmodus mit Animation angezeigt werden. Wenn sie geschlossen wird, kann ich sowohl die Sammlungsansicht als Hintergrundansicht als auch die animierte Detailansicht anzeigen.

Dann noch eine Entdeckung entlang der Straße

3.Um auf 'toView' und 'fromView' zu verweisen, funktionieren beide folgenden Methoden

Indirekt:

transitionContext.viewController(forKey: .to)?.view
transitionContext.viewController(forKey: .from)?.view

Direkt Weg:

transitionContext.view(forKey: .to)
transitionContext.view(forKey: .from)

Aber als ich den Segue-Stil auf "Over Full Screen" umgestellt habe, gibt der direkte Weg "nil" sowohl für "toView" als auch für "fromView" zurück und funktioniert nur indirekt. Dieses Problem wird auch in einem anderen Beitrag erwähnt , daher denke ich, dass es sich lohnt um meine kleine Entdeckung hier zu posten.

Hoffe, dass dies in Zukunft für jemanden hilfreich sein wird.


0

Ich hatte das gleiche Problem beim Entlassen eines Inhaltsansichts-Controllers.

In meiner App zeigt dieser übergeordnete Ansichts-Controller einen untergeordneten Ansichts-Controller (der vc darstellt) modal an. Wenn dann auf eine Unteransicht in der untergeordneten VC getippt wird, wird eine andere VC angezeigt (die ich als Inhaltsansichts-Controller bezeichne (präsentierte VC)).

Mein Problem ist, dass beim Verwerfen der contentVC (jetzt der präsentierenden VC) die untergeordnete VC (jetzt die präsentierte VC) angezeigt wird. Sobald mein benutzerdefinierter Übergang abgeschlossen ist, verschwindet die untergeordnete VC plötzlich und zeigt die übergeordnete VC an.

Was ich getan habe, um dieses Problem zu lösen, ist zu

  1. ändere das .modalPresentationStyle von parentVC präsentierte childVC von der Standardeinstellung .automaticin.fullscreen .
  2. Dann änderte sich die .modalPresentationStyle von contentVC auf.fullscreen .

Dies löst das Problem. Ihr Kind VC wird jedoch nicht als Kartenblatt über parentVC angezeigt (bei Verwendung).overCurrentContext oder automatisch) das in iOS 13 neu ist.

Würde gerne wissen, ob es eine Lösung gibt, die das Kartenformat für das childVC beibehält, wenn es vom Elternteil präsentiert wird.


-3

Fügt einen View Controller als untergeordnetes Element eines anderen View Controllers hinzu.

[self addChildViewController:childViewController];                 

Überprüfen Sie und lassen Sie es mich wissen.


Ich verstehe nicht, können Sie es mit Codierung beschreiben?
NiravPatel

Überprüfen Sie diese Apple-Dokumentation developer.apple.com/library/ios/featuredarticles/…
Rushabh

Dies beantwortet in keiner Weise die Frage. ChildViewController sind an keinem Teil von benutzerdefinierten Übergängen beteiligt, sie sind ein völlig anderes Thema.
Andras M.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.