"From View Controller" scompare utilizzando UIViewControllerContextTransitioning


105

Ho un problema e l'ho descritto di seguito.

sto usando UIViewControllerContextTransitioning per le transizioni personalizzate.

Ho 2 controller di visualizzazione, il primo controller di visualizzazione e il secondo controller di visualizzazione.

Ora voglio aggiungere il secondo controller di visualizzazione sul primo controller di visualizzazione con un'animazione. Ci sono riuscito, ora il secondo controller di visualizzazione è trasparente, quindi possiamo vedere il primo controller di visualizzazione sotto il secondo controller di visualizzazione.

Ma non sono in grado di vedere il primo controller di visualizzazione e posso vedere solo lo schermo nero sotto il secondo controller di visualizzazione.

-(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];
    }];
}

quando [self.transitionContext completeTransition:YES]; chiamato, improvvisamente il primo controller di visualizzazione scompare e lo schermo nero viene visualizzato sotto il secondo controller di visualizzazione.

Qualcuno ha idea? Grazie.

Risposte:


98

Ho riscontrato lo stesso problema qui: sembra un bug in iOS 8. Ho presentato un radar .

Ho usato Reveal per ispezionare la gerarchia della visualizzazione dopo che lo schermo è diventato nero. La chiave UIWindowè completamente vuota: nessuna gerarchia di visualizzazione!

Reveal'd

Ho giocato un po 'e sembra che ci sia una soluzione facile, per casi semplici. Puoi semplicemente aggiungere nuovamente la toViewControllervista di come una sottoview della finestra chiave:

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

Ho controllato e la finestra della chiave rootViewControllerè ancora impostata correttamente, quindi va bene. Non sono sicuro di cosa succederebbe se presentassi il tuo controller da un controller modale già presentato, quindi per casi più complessi, dovrai sperimentare.


2
Ho visto anche questo problema. iOS 8 introduce un nuovo metodo e tasti per accedere a fromView e toView (Nota: non visualizza controller) Sembra che questi riferimenti non vadano persi durante la transizione. Puoi aggiungerli alla visualizzazione del contenitore come faresti normalmente se li avessi appena recuperati dai controller di visualizzazione.
tapi

1
Stavo vedendo una stranezza simile in iOS 8 quando cercavo di aggiungere sottoview alla vista del mio controller di navigazione, in viewDidLoad. Aggiungere nuovamente la vista del navigationController alla chiave La finestra sembrava fare il trucco, grazie mille, Ash!
taber

1
Lo vedo ancora in GM (e questa correzione funziona ancora). Gli altri vedono lo stesso? È solo una modifica nell'API?
rjkaplan

21
Ho scoperto che questo bug (e molti altri!) Svanisce se imposti modalPresentationStyle = UIModalPresentationFullScreen. Ovviamente ottieni ancora la tua animazione di transizione personalizzata.
Chris

1
Grazie @AshFurrow. Bella soluzione fino a quando non viene risolto!
kandelvijaya

78

Sento che il ragionamento alla base di questo dovrebbe essere spiegato meglio.

La vista scompare perché estrai la vista del controller della vista che presenta dalla sua posizione originale (gerarchia della vista), la metti all'interno del containerView che il tuo animatore fornisce ma non la restituisce mai dopo che l'animazione è terminata. In modo che la vista del controller di visualizzazione venga rimossa completamente dalla finestra con la sua superview (containerView).

In iOS 7 il sistema ha sempre restituito le visualizzazioni dei controller di visualizzazione che sono coinvolti nella presentazione (presentazione e presentazione) nelle posizioni originali dopo che la transizione ha terminato l'animazione automatica. Ciò non accade più per alcuni stili di presentazione in iOS 8.

La regola è molto semplice: l'animatore dovrebbe manipolare la vista del controller di visualizzazione che presenta solo se la visualizzazione di quel controller di visualizzazione sarà completamente nascosta (rimossa dalla gerarchia di visualizzazione) entro la fine della transizione . In altre parole, significa che al termine dell'animazione della presentazione iniziale sarà visibile solo la vista del controller di visualizzazione presentato e non quella del controller di visualizzazione che presenta. Ad esempio, se imposti l'opacità della vista del controller della vista presentata al 50% e utilizzi UIModalPresentationFullScreen, non sarai in grado di vedere la vista del controller della vista della presentazione sotto la vista presentata ma se usi UIModalPresentationOverFullscreen - lo farai (UIPresentationController'sshouldRemovePresentersView metodo è responsabile di specificarlo).

Perché non consentire all'animatore di manipolare la vista del controller della vista che presenta in ogni momento? Prima di tutto, se la vista del controller della vista di presentazione rimarrà visibile al termine dell'animazione durante l'intero ciclo di vita della presentazione, non è affatto necessario animarla: rimane semplicemente dove si trova. In secondo luogo, se la proprietà per quel controller di visualizzazione viene trasferita al controller di presentazione, molto probabilmente il controller di presentazione non saprà come disporre la visualizzazione di quel controller di visualizzazione quando necessario, ad esempio quando cambia l'orientamento, ma il proprietario originale del controller di visualizzazione di presentazione lo fa .

In iOS 8 viewForKey:è stato introdotto il metodo per ottenere visualizzazioni manipolate dall'animatore. Innanzitutto, aiuta a seguire la regola sopra descritta restituendo zero ogni volta che l'animatore non deve toccare la vista. In secondo luogo, potrebbe restituire una vista diversa per l'animatore. Immagina di implementare una presentazione simile al foglio modulo. In questo caso, si desidera aggiungere un'ombra o una decorazione attorno alla vista del controller di visualizzazione presentato. L'animatore animerà invece quella decorazione e la vista del controller di visualizzazione presentato sarà una figlia della decorazione.

viewControllerForKey: non scompare, può ancora essere utilizzato se è necessario un accesso diretto ai controller di visualizzazione ma l'animatore non deve fare supposizioni sulle visualizzazioni di cui ha bisogno per animare.

Ci sono diverse cose che puoi fare per risolvere correttamente un problema con la visualizzazione di un controller di visualizzazione di presentazione che scompare quando lo inserisci esplicitamente nella visualizzazione del contenitore dell'animatore:

  1. Se non è necessario animare la vista del controller della vista che presenta, utilizzare viewForKey:per ottenere le viste da animare invece di raggiungere direttamente le viste del controller. viewForKey:può restituire punti di vista nulli o addirittura completamente diversi.

  2. Se si desidera animare la vista dei controller della vista di presentazione, è necessario considerare l'utilizzo dello UIModalPresentationFullScreenstile o continuare a utilizzare UIModalPresentationCustome implementare la propria sottoclasse di UIPresentationController con shouldRemovePresentersViewrestituzione YES. In effetti, l'implementazione di questo metodo è la principale differenza tra i controller di presentazione interni definiti da UIModalPresentationFullScreene gli UIModalPresentationCustomstili a parte il fatto che quest'ultimo consente di utilizzare controller di presentazione personalizzati.

  3. In tutti gli altri rari casi sarà necessario riportare la visualizzazione del controller della vista di presentazione alla posizione originale come suggerito da altre risposte.


2
È molto strano perché questo codice si basa su viewControllerForKey:di s viewsolo quando viewForKey:restituisce zero, e ho dovuto comunque aggiungerlo di nuovo manualmente alla finestra. Hai un esempio di codice che funziona senza questa soluzione alternativa?
Ash Solrow

Bene, se viewForKey:restituisce zero, sicuramente dovrai aggiungere nuovamente la vista del controller della vista di presentazione alla finestra se la rimuovi da essa nel tuo animatore. Nel caso in cui viewForKey restituisca la vista del controller di visualizzazione effettivo, è sicuro spostare quella vista perché UIKit la sposterebbe nella sua posizione originale al termine del ciclo di vita della presentazione.
egdmitry

Grazie per aver spiegato il ragionamento alla base di questo problema. Hai assolutamente ragione. Spostare la posizione della vista nella gerarchia della vista senza sostituirla ovviamente la farebbe scomparire (post iOS 8 e sto lavorando con iOS 10 in questo momento!) Grazie per aver chiarito.
Clay Ellis

1
Grazie egdmitry per il tuo chiarimento. Il che solleva un'altra domanda che è: come pensi che dovrei implementare una presentazione come rivelare ? Uno di quelli molto comuni oggigiorno in cui la vista di presentazione scorre parzialmente per mostrare la vista presentata sotto? In questo scenario sia la visualizzazione di presentazione che quella presentata devono essere sullo schermo e la visualizzazione di presentazione è quella animata.
Andrea

70

In iOS 8, è necessario modificare le visualizzazioni restituite da viewForKey:anziché la .viewproprietà dei controller di visualizzazione restituiti da viewControllerForKey:. Questo non è particolarmente chiaro dalla documentazione beta, ma se guardi nella fonte per UIViewControllerTransitioning.h vedrai questo commento sopra 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;

Quindi, invece di regolare i frame, ecc. toViewController.view, Usa il valore restituito di[transitionContext viewForKey:UITransitionContextToViewKey] .

Se la tua app deve supportare iOS7 e / o Xcode 5, puoi utilizzare un semplice metodo di categoria su UIViewController come il seguente:

- (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
}

Quindi, prendi il tuo toViewControllere fromViewControllercome al solito, ma ottieni le visualizzazioni usando[toViewController viewForTransitionContext:transitionContext] .

Modifica: sembra esserci un bug, in cui la vista del controller della vista di presentazione è nulla quando viene restituita viewForKey, il che impedisce di effettuare transizioni modali che animano la vista di presentazione (come lo scorrimento o il ribaltamento orizzontale). Ho segnalato un bug per iOS8 su rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Vedi anche il progetto di esempio su http://github.com/bcherry/TransitionBug

Modifica 2: Grazie a Graveley per il suggerimento, l'utilizzo di UIModalPresentationFullScreen risolve il problema. Forse questo non è un bug. Apple può prevedere che UIModalPresentationCustom modifichi solo la visualizzazione del modale in arrivo. Se vuoi modificare la vista in uscita, devi garantire la presentazione a schermo intero della nuova vista? In ogni caso, dovresti usare viewForKeye UIModalPresentationFullScreen.


2
Il bug di viewForKey mi stava facendo impazzire! - grazie per la presentazione. FWIW la mia transizione funziona correttamente ottenendo la vista da UITransitionContextToViewControllerKey, ma la mia transizione applica solo una trasformazione all'intera vista. Non sono sicuro se questo dovrebbe essere interpretato come manipulatingle opinioni dei VC o no ...
MathewS

1
Wow, è pazzesco. Non l'ho visto nelle differenze, probabilmente perché è solo un piccolo commento. Davvero frustrante quando Apple fa un'acrobazia come questa. Incrociamo le dita sul tuo radar.
Ash Solrow

Vedo anche il viewForKeybug nel GM. Lo sono anche gli altri? Hai trovato una soluzione ragionevole per questo?
rjkaplan

2
Secondo il commento di - viewForKey// viewForKey, ho pensato : potrebbe restituire zero, il che indicherebbe che l'animatore non dovrebbe manipolare la vista del controller di visualizzazione associato. Il ritorno nilnon è un bug.
Ken Kuan,

4
@kenKuan potresti avere ragione. quando si utilizza UIModalPresentationFullScreen, viewForKeyrestituisce la vista da e la vista. Quindi forse è intenzionale che restituisca zero per UIModalPresentationCustom. Sto aggiornando la mia segnalazione di bug e pubblicherò di nuovo qui se ricevo notizie da Apple in merito.
bcherry

24

Non l'impostazione modalPresentationStyle su UIModalPresentationCustom ha risolto il problema per me.

In altre parole, lasciare il valore predefinito di UIModalPresentationFullScreen invece di specificare UIModalPresentationCustom ha risolto il problema della scomparsa della vista. Si noti che il protocollo UIViewControllerTransitioningDelegate sembra ancora essere seguito anche quando si lascia l'impostazione predefinita. Se ricordo bene, una volta UIModalPresentationCustom era un requisito.

Funziona finora, l'ho provato solo per animazioni non interattive.


1
Wow. È stato così! Ho provato senza modalPresentationStyle in iOS7 e 8 e funziona in entrambi. Grazie!!
Ah Ryun Moon

1
Grazie! Questo combinato con l'utilizzo viewForKey:invece che .viewsulle viewControllerForKey:risolve tutti i problemi per me.
bcherry

1
Questo ha risolto il problema per me senza usare viewForKey, ma suppongo che dovrebbe essere usato anche.
Kevin Sliech

5
Sebbene questo sembri risolvere il problema, è importante notare che lo schermo dietro il controller della vista diventerà nero una volta visualizzato. Questo è importante se il controller della vista non è a schermo intero.
Il tizio

16

Ho trovato questa risposta estremamente utile in un thread correlato di Lefteris: https://stackoverflow.com/a/27165723/3709173

Riassumendo:

  1. imposta modalPresentationStyle su .Custom
  2. sottoclasse UIPresentationController, sovrascrivi shouldRemovePresentersView (con NO)
  3. eseguire l'override di presentationControllerForPresentedViewController nella classe TransitionDelegate e restituire il UIPresentationController personalizzato

+1 nella transizione personalizzata, non aggiungere a Visualizza quando è in corso l'animazione di eliminazione.

Dimostrato qui:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 senza alcun hack! è come una magia! :)


1
Questa è la vera risposta giusta. Senza trucchi magici come in quello accettato. Grazie, Mark!
Andrei Malygin

Sfortunatamente, questo non funziona in iOS 12.4, Xcode 10.3. Lo schermo diventa nero al termine della transizione (tutte le visualizzazioni sono state rimosse dalla gerarchia. Tuttavia, l'impostazione della proprietà "modalPresentationStyle" su ".fullscreen" FUNZIONA. Saluti.
Womble

Ho provato la versione Obj-C da Mark e l'implementazione Swift di gwinyai nel mio progetto. Purtroppo nessuno di loro funziona come previsto. Sto usando Xcode 11.1 e l'obiettivo di build è iOS 13.0, ho provato sia sul dispositivo che sul simulatore. Nel mio caso, la mia configurazione di base è una vista di raccolta e quando tocchi una cella seguirà una vista di dettaglio con animazione. Tuttavia, funziona perfettamente se utilizzo l'animazione di transizione predefinita. Il VC di presentazione non sparirà quando riprenderò dai dettagli la visualizzazione.
infinity_coding7

8

In iOS 8, è necessario creare un UIPresentationController e implementare il metodo seguente, in UIViewControllerTransitioningDelegate.

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

Chiede al delegato di utilizzare il controller di presentazione personalizzato per la gestione della gerarchia di visualizzazione durante la presentazione di un controller di visualizzazione.

Valore di ritorno:

Il controller di presentazione personalizzato per la gestione della presentazione modale.

Discussione:

Quando si presenta un controller di visualizzazione utilizzando lo stile di presentazione UIModalPresentationCustom, il sistema chiama questo metodo e richiede il controller di presentazione che gestisce lo stile personalizzato. Se si implementa questo metodo, utilizzarlo per creare e restituire l'oggetto controller di presentazione personalizzato che si desidera utilizzare per gestire il processo di presentazione.

Se non si implementa questo metodo o se l'implementazione di questo metodo restituisce zero, il sistema utilizza un oggetto controller di presentazione predefinito. Il controller di presentazione predefinito non aggiunge visualizzazioni o contenuto alla gerarchia di visualizzazione.

Disponibilità Disponibile in iOS 8.0 e versioni successive.

Per maggiori informazioni guarda il video del WWDC 2014:

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

C'è anche un codice di esempio dal WWDC chiamato "LookInside: Presentation Controller Adaptivity and Custom Animator Objects", che puoi scaricare dalla pagina di codice di esempio del WWDC 2014.

Potrebbe essere necessario modificare un po 'il codice di esempio. Il metodo di inizializzazione UIPresentationController è stato modificato in:

initWithPresentedViewController:presented presentingViewController:presenting

Prima era presentare e poi presentato. Basta scambiarli e dovrebbe funzionare.


Ci scusiamo per non aver guardato il video collegato, ma non penso che tu abbia bisogno di un UIPresentationController personalizzato a meno che tu non voglia una presentazione non standard dopo il completamento dell'animazione, come una vista presentata circolare. Se vuoi solo un'animazione diversa, l'implementazione di UIViewControllerAnimatedTransitioning dovrebbe essere sufficiente, in base alla mia conoscenza limitata.
Vaddadi Kartick

7

invece di [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; basta aggiungere: [inView addSubview: toViewController.view];

if (self.presenting) {

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

} else {
    // your code
}

Puoi vedere un esempio qui: link e funziona su iOS 7 e iOS 8


Questa dovrebbe essere la risposta accettata per eseguire un tipo di animazione UIModalPresentationStyleCustom poiché non è necessario aggiungere fromViewController a containerView. Devi solo aggiungere toViewController durante l'animazione di presentazione.
Scott Kaiser

Questo è molto utile, in realtà
Dmitry Bondarev

7

Ecco una versione Objective C della correzione di Ash.

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

Ho dovuto scambiare l'ordine e chiamare il metodo [TransitionContext completeTransition:] dopo aver aggiunto di nuovo la visualizzazione per far funzionare correttamente un nuovo controller di visualizzazione dal blocco di completamento del licenziamento di un altro controller di visualizzazione.

Non so se questo lo risolverà per tutti, ma funziona nella mia app. Saluti!


5

Ho trovato che funzionava bene per Obj-C:

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

Sembra funzionare bene sia su ios7 che su ios8.


5

l'ho trovato viewForKey:UITransitionContextToViewKey restituisce zero su iOS8. Quindi, se è zero, prendo la vista dal controller di visualizzazione "a".

Tuttavia, sembra che la visualizzazione "a" non venga spostata dal contenitore alla finestra quando completeTransition:YESviene chiamata. Quindi se viewForKey:UITransitionContextToViewKeyrestituisce zero, cado atoVC.view e tengo traccia del fatto che è tornato zero, e dopo il completamento lo sposto nella superview iniziale del contenitore (che sembra essere la finestra).

Quindi questo codice funziona su iOS7 e iOS8 e dovrebbe funzionare anche su iOS9 anche se lo risolvono o meno.

- (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

Ho scoperto che questo bug (e molti altri!) Svanisce se imposti modalPresentationStyle = UIModalPresentationFullScreen. Ovviamente ottieni ancora la tua animazione di transizione personalizzata.


2

Anch'io sono rimasto bloccato su questo problema. Stavo cercando di creare una transizione personalizzata con uno sfondo semitrasparente in cui potevo ancora vedere il controller della vista da cui provenivo ma ho ottenuto solo uno sfondo nero. Ho trovato la risposta di Mark Aron in questo thread mi ha aiutato, ma è scritta in Objective C, quindi ecco una versione Swift 3 di quella risposta che ho testato per iOS 9 e iOS 10:

  1. Crea una sottoclasse di UIPresentationController. Eseguire l'override di shouldRemovePresentersView su false come segue:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. Nel punto in cui si crea un'istanza del nuovo controller di visualizzazione e si imposta il suo delegato di transizione, indicare che si desidera che mostri uno stile di presentazione modale personalizzato come segue:

    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. Ora sovrascrivi il metodo presentationController del tuo UIViewControllerTransitioningDelegate e restituisci il tuo UIPresentationController personalizzato. Ho avuto il mio come estensione alla mia classe attuale:

    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)
    
    }
    }

Un'altra cosa da notare è che non dovresti provare a fare riferimento al tuo fromView nella tua classe presentAnimator. Questo sarà nullo e riceverai un errore in fase di esecuzione. Oltre a questo, se implementi cose come cose, otterrai la tua transizione personalizzata con la sua animazione e uno sfondo semitrasparente se ne fai uno.


Questo iis è un ottimo esempio per fare una presentazione modale personalizzata in Swift 3! Grazie @gwinyai! Sono rimasto bloccato su questo fino a quando non ho trovato un esempio che mostrava la nuova API swift 3 presentationController(forPresented presented UIViewController,... perché la precedente API swift non ha sconvolto il compilatore ma non è stata chiamata.
Natalia

2

Dopo aver riscontrato questo problema, ero molto confuso, perché non molto tempo fa avevo scritto qualcosa di quasi identico che funzionava bene. Sono venuto qui alla ricerca di risposte per trovare soluzioni che sembrano piuttosto complicate e non sembrano capire la causa principale ... in realtà è molto facile da risolvere.

Alcune risposte menzionano il passaggio modalPresentationStylea .overFullScreen. Questo è corretto, .overCurrentContextfunzionerebbe anche. Questo è previsto e il comportamento dei documenti Apple. Ma perché non funziona per tutti? Perché tutto il codice hacker e le combinazioni di questo con qualcos'altro e cose pazze che non dovresti fare?

Risulta, è necessario impostare lo stile di presentazione PRIMA CHE LA VISUALIZZAZIONE SI CARICHI . Non dopo. Fallo in init, o dal controller precedente, o come preferisci, purché sia ​​prima del caricamento della vista.


1
Ho impostato lo stile di presentazione su .overCurrentContext prima del caricamento della vista (nel initcontroller della vista) e il problema si verifica ancora
ricardopereira

1

L'utilizzo del nuovo UIModalPresentationOverCurrentContext lo ha risolto per me. La mia transizione originale su iOS 7 era solo di avere uno sfondo sfocato della vista sotto il modale.


Per qualche ragione, questo non sembra consentire l'interazione con la vista sottostante, dove UIModalPresentationCurrentContext ha fatto in iOS 7 .. Qualche idea?
Christopher Wirt

Hmm per me su iOS 10, .overCurrentContext provoca questo bug ma .fullscreen no. Sono venuto qui sperando in una soluzione per l'utilizzo di .overCurrentContext ma finora nulla sembra funzionare in iOS 10 tranne forse la sottoclasse di UIPresentationController ...
Natalia

0

Ok, ragazzi, penso di aver risolto un caso in cui "un animatore funzionante" smette di funzionare correttamente quando si crea un'app in iOS 13 e versioni successive.

Env Xcode 11.1, iOS 13.1

Problema

Quello che voglio fare è molto semplice: ho una visualizzazione raccolta, quando una cella viene toccata, seguirà una visualizzazione dettagliata. Invece di usare il noioso stile predefinito di "present modally", voglio renderlo più interessante, quindi ho scritto un animatore per la transizione del controller di visualizzazione.

Ho impostato il segue in IB trascinando dalla mia raccolta VC al dettaglio VC. Lo stile di segue è "Presenta in modo modale" e la presentazione è impostata su "Schermo intero".

Quando mostra la visualizzazione dei dettagli, tutto funziona come previsto. Tuttavia, quando chiudo la visualizzazione dei dettagli e ritorno alla visualizzazione della raccolta, posso vedere solo la visualizzazione dei dettagli animata, la visualizzazione della raccolta è semplicemente scomparsa. Ho toccato qua e là e ho alcune scoperte

1) Subito dopo che la riga seguente è stata chiamata dalla funzione 'animateTransition ()', la vista della raccolta riprende e si presenta

transitionContext.completeTransition(true)

2.Finché la vista dei dettagli non copre completamente la vista della raccolta, la vista della raccolta non scomparirà quando ritorna dalla vista dei dettagli

Soluzione

Ad essere onesti, so poco di come funziona la transizione animata. Quindi posso solo seguire questo post e l'altro , provare ciascuna delle risposte. Sfortunatamente, nessuno di loro funziona per me. Alla fine, sono arrivato a un punto in cui l'unica cosa che posso modificare è lo stile di presentazione di segue in IB (cosa che avrei dovuto fare all'inizio). Quando imposto la presentazione su "Over Full Screen", accade il miracolo e il mio problema è risolto. La visualizzazione dei dettagli potrebbe essere mostrata a schermo intero con animazione e quando viene chiusa, posso vedere sia la visualizzazione della raccolta come sfondo che la visualizzazione dettagliata animata.

Poi un'altra scoperta lungo la strada

3.Per fare riferimento a "toView" e "fromView", funzionano entrambi i metodi seguenti

Indirettamente modo:

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

Direttamente in modo:

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

Ma quando ho cambiato lo stile Segue su "Over Full Screen", il modo diretto restituisce "nil" sia per "toView" che per "fromView" e funziona solo indirettamente, questo problema è menzionato anche in un altro post , quindi penso che valga la pena postare qui la mia piccola scoperta.

Spero che questo possa essere utile a qualcuno in futuro.


0

Ho riscontrato lo stesso problema durante la chiusura di un controller di visualizzazione del contenuto.

La mia app ha questo controller di visualizzazione genitore che mostra un controller di visualizzazione figlio (che presenta vc) in modo modale. Quindi, quando viene toccata una sottoview nel childVC, mostra un altro vc (che sto chiamando il controller della visualizzazione del contenuto (presentato vc))

Il mio problema è che, quando si elimina il contentVC (ora il vc presentante), dovrebbe andare al child VC (ora il VC presentato) ma non appena la mia transizione personalizzata finisce, childVC scompare improvvisamente, mostrando il genitore VC.

Quello che ho fatto per risolvere questo problema è

  1. cambia il .modalPresentationStyledel childVC presentato da parentVC dal valore predefinito .automatica .fullscreen.
  2. Quindi ha cambiato anche il .modalPresentationStyledi contentVC in .fullscreen.

Questo risolve il problema. ma non mostrerà il tuo bambino VC come un foglio stile carta sopra parentVC (quando usi.overCurrentContext o automatico) che è nuovo in iOS 13.

Mi piacerebbe sapere se esiste una soluzione che conserverà il foglio stile carta per il bambinoVC quando presentato dal genitore.


-3

aggiunge un controller di visualizzazione come figlio di un altro controller di visualizzazione.

[self addChildViewController:childViewController];                 

controlla e fammi sapere.


non ottengo, puoi descriverlo usando la codifica?
NiravPatel

controlla questa documentazione Apple developer.apple.com/library/ios/featuredarticles/…
Rushabh

questo non risponde in alcun modo alla domanda. I ChildViewControllers non sono coinvolti in nessuna parte delle transizioni personalizzate, sono un argomento completamente diverso.
Andras M.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.