2011-11-08 12 views
13

Analogamente a been reported in altre domande qui su SO, iOS 5 cambia il modo in cui le richiamate di rotazione per i controllori di vista divisa vengono inviate come da questa nota di rilascio. Questa non è una vittima (credo), in quanto non riesco a trovare un'altra domanda sul SO che si occupa di come regolare divisa utilizzo View Controller in iOS 5 per far fronte al cambiamento:iOS5 interrompe i callback di rotazione di UISplitViewController, come richiamare manualmente?

callback rotazione in iOS 5 non vengono applicati per visualizzare i controller che sono visualizzati su uno schermo intero. Ciò significa che se il codice presenta un controller di vista rispetto ad un altro controllore vista, e quindi l'utente successivamente ruota il dispositivo ad un orientamento diverso, su dimissione, il controllore sottostante (regolatore cioè presentando) sarà non riceverà alcuna rotazione callback. Si noti tuttavia che il controller presenterà una chiamata viewWillLayoutSubviews quando è nuovamente visualizzata e la proprietà interfaceOrientation può essere interrogata da questo metodo e utilizzata per disporre correttamente il controller.

Ho problemi a configurare il tasto popover nel mio principale divisa controller della vista (quello che dovrebbe mostrare la vista riquadro di sinistra in un popover quando si è in modalità ritratto). Ecco come la mia app sequenza di avvio utilizzato per lavorare in iOS 4.x quando il dispositivo è in modalità orizzontale:

  1. Installare controller di vista divisa in finestra con [window addSubview:splitViewController.view]; [window makeKeyAndVisible];. Ciò comporta che splitViewController:willHideViewController:withBarButtonItem:forPopoverController: venga chiamato sul delegato (ad esempio simulando un paesaggio -> rotazione verticale) anche se il dispositivo è già in modalità orizzontale.

  2. Presenta un modal a schermo intero (la mia schermata di caricamento) che copre completamente la vista divisa sotto.

  3. Completare il caricamento e chiudere la schermata di caricamento modal. Dato che il dispositivo è in modalità orizzontale, quando viene rivelato il controller della vista divisa, questo fa sì che splitViewController:willShowViewController:invalidatingBarButtonItem: venga chiamato sul delegato (ovvero simula un ritratto -> rotazione del paesaggio), invalidando quindi la voce del pulsante della barra, rimuovendola dal lato destro della visione divisa, e lasciandoci dove vogliamo essere. Evviva!

Quindi, il problema è che, a causa del cambiamento descritto in tale nota di rilascio, qualunque accade internamente IOS 4.3 che si traduce in splitViewController:willShowViewController:invalidatingBarButtonItem: essere chiamato non accade in IOS 5. Ho provato sottoclasse UISplitViewController così ho potuto fornire un'implementazione personalizzata di viewWillLayoutSubviews come suggerito dalla nota di rilascio, ma non so come riprodurre la sequenza desiderata di eventi interni avviata da iOS 4. Ho provato questo:

- (void) viewWillLayoutSubviews 
{ 
    [super viewWillLayoutSubviews]; 

    UINavigationController *rightStack = [[self viewControllers] objectAtIndex:1]; 
    UIViewController *rightRoot = [[rightStack viewControllers] objectAtIndex:0]; 
    BOOL rightRootHasButton = ... // determine if bar button item for portrait mode is there 

    // iOS 4 never goes inside this 'if' branch 
    if (UIInterfaceOrientationIsLandscape([self interfaceOrientation]) && 
     rightRootHasButton) 
    { 
     // Manually invoke the delegate method to hide the popover bar button item 
     [self.delegate splitViewController:self 
        willShowViewController:[[self viewControllers] objectAtIndex:0] 
       invalidatingBarButtonItem:rightRoot.navigationItem.leftBarButtonItem]; 
    } 
} 

Questo funziona per lo più, ma non al 100%. Il problema è che invocare da solo il metodo delegato non è in realtà invalidare la voce del pulsante della barra, quindi la prima volta che si ruota in verticale, il sistema pensa che l'elemento del pulsante della barra sia ancora installato correttamente e non provi a reinstallarlo. È solo dopo aver ruotato di nuovo in orizzontale e poi di nuovo in verticale il sistema è tornato nello stato giusto e in realtà installerà l'elemento del pulsante della barra popover in modalità verticale.

Sulla base this question, ho anche provato invocando tutti i richiami rotazione manualmente invece di sparare il metodo delegato, ad esempio:

// iOS 4 never goes inside this 'if' branch 
if (UIInterfaceOrientationIsLandscape([self interfaceOrientation]) && 
    rightRootHasButton) 
{ 
    [self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0]; 
    [self willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0]; 
    [self didRotateFromInterfaceOrientation:self.interfaceOrientation]; 
} 

Tuttavia questo sembra solo per causare un ciclo infinito di nuovo in viewWillLayoutSubviews :(

Qualcuno sa che il modo corretto per simulare gli eventi di rotazione in stile iOS4 è per un controller della vista che appare diviso da dietro a una modal a schermo intero? O non dovresti simularli affatto? Esiste un altro approccio best-practice che è diventato lo standard per iOS5?

Qualsiasi aiuto davvero apprezzato visto che questo problema ci trattiene dall'invio del nostro iOS5 versione bugfix su App Store.

risposta

11

Non conosco il modo giusto per gestire questa situazione. Tuttavia, il seguente sembra funzionare per me in iOS 5.

  1. In splitViewController:willHideViewController:withBarButtonItem:forPopoverController:, memorizzare un riferimento al barButtonItem in qualcosa di simile self.barButtonItem. Sposta il codice per mostrare il pulsante in un metodo separato, ad esempio ShowRootPopoverButtonItem.

  2. In splitViewController:willShowViewController:invalidatingBarButtonItem:, deselezionare il riferimento self.barButtonItem. Sposta il codice per mostrare il pulsante in un metodo separato, ad esempio InvalidateRootPopoverButtonItem.

  3. In viewWillLayoutSubviews, mostrano manualmente o nascondere il pulsante, a seconda dell'orientamento dell'interfaccia

Ecco la mia implementazione di viewWillLayoutSubviews. Si noti che la chiamata self.interfaceOrientation restituiva sempre un ritratto, quindi il mio uso di statusBarOrientation.

- (void)viewWillLayoutSubviews 
{ 
    if (UIInterfaceOrientationIsPortrait(
     [UIApplication sharedApplication].statusBarOrientation)) 
    { 
     [self ShowRootPopoverButtonItem:self.barButtonItem]; 
    } 
    else 
    { 
     [self InvalidateRootPopoverButtonItem:self.barButtonItem]; 
    } 
} 
+1

Hey Noè - grazie per la soluzione - si sta lavorando anche per me. È un po 'sfortunato perché viewWillLayoutSubviews è chiamato molto più spesso di quanto lo siano gli eventi di rotazione, quindi stipare tutto il pulsante che nasconde/mostra la logica in esso significa che viene eseguito molto più spesso, ma sembra che questo sia il modo iOS5 di fare questa roba ora. – glenc

Problemi correlati