iOS5 rompe las devoluciones de llamada de rotación de UISplitViewController, ¿cómo invocar manualmente?

Como tiene sido reportado En otras preguntas aquí en SO, iOS 5 cambia la forma en que se envían las devoluciones de llamada de rotación para los controladores de vista dividida según esta nota de la versión. Esto no es un engaño (creo), ya que no puedo encontrar otra pregunta en SO que trate sobre cómo ajustar el uso del controlador de vista dividida en iOS 5 para hacer frente al cambio:

Las devoluciones de llamada de rotación en iOS 5 no se aplican a los controladores de vista que se presentan en una pantalla completa. Lo que esto significa es que si su código presenta un controlador de vista sobre otro controlador de vista, y luego el usuario posteriormente gira el dispositivo a una orientación diferente, al descartarlo, el controlador subyacente (es decir, el controlador de presentación) no recibirá ninguna devolución de llamada de rotación. Sin embargo, tenga en cuenta que el controlador de presentación recibirá una llamada viewWillLayoutSubviews cuando se vuelva a mostrar, y la propiedad interfaceOrientation se puede consultar desde este método y utilizar para diseñar el controlador correctamente.

Tengo problemas para configurar el botón de ventana emergente en mi controlador de vista dividida raíz (el que se supone que muestra la vista del panel izquierdo en una ventana emergente cuando estás en vertical). Así es como solía funcionar la secuencia de inicio de mi aplicación en iOS 4.x cuando el dispositivo está en modo horizontal:

  1. Instale el controlador de vista dividida en la ventana con [window addSubview:splitViewController.view]; [window makeKeyAndVisible];. Esto resulta en splitViewController:willHideViewController:withBarButtonItem:forPopoverController: ser llamado al delegado (es decir, simulando un paisaje -> rotación vertical) aunque el dispositivo ya esté en modo horizontal.

  2. Presente un modal de pantalla completa (mi pantalla de carga) que cubra completamente la vista dividida debajo.

  3. Termine de cargar y descarte el modal de la pantalla de carga. Dado que el dispositivo está en modo horizontal, cuando se revela el controlador de vista dividida, esto causa splitViewController:willShowViewController:invalidatingBarButtonItem: ser llamado al delegado (es decir, simulando un retrato -> rotación horizontal), invalidando así el elemento del botón de la barra, eliminándolo del lado derecho de la vista dividida y dejándonos donde queremos estar. ¡Hurra!

Entonces, el problema es que debido al cambio descrito en esa nota de la versión, cualquier cosa que suceda internamente en iOS 4.3 resulte en splitViewController:willShowViewController:invalidatingBarButtonItem: ser llamado ya no ocurre en iOS 5. Intenté subclasificar UISplitViewController para poder proporcionar una implementación personalizada de viewWillLayoutSubviews como sugiere la nota de la versión, pero no sé cómo reproducir la secuencia deseada de eventos internos que activa iOS 4. Probé esto:

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

Esto funciona principalmente, pero no al 100%. El problema es que invocar el método de delegado usted mismo no Realmente invalidar el elemento del botón de la barra, por lo que la primera vez que lo gira a vertical, el sistema cree que el elemento del botón de la barra todavía está instalado correctamente y no intenta reinstalarlo. Solo después de girar nuevamente a horizontal y luego de vuelta a vertical, el sistema regresó al estado correcto y realmente instalará el elemento del botón de la barra emergente en modo vertical.

Basado en esta pregunta, También intenté invocar todas las devoluciones de llamada de rotación manualmente en lugar de activar el método delegado, por ejemplo:

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

Sin embargo, esto solo parece causar un bucle infinito en viewWillLayoutSubviews :(

¿Alguien sabe cuál es la forma correcta de simular los eventos de rotación al estilo de iOS4 para un controlador de vista dividida que aparece detrás de un modo de pantalla completa? ¿O no debería simularlos en absoluto y hay otro enfoque de mejores prácticas que se ha convertido en el estándar para iOS5?

Realmente apreciamos cualquier ayuda, ya que este problema nos impide enviar nuestra versión de corrección de errores de iOS5 a la App Store.

preguntado el 08 de noviembre de 11 a las 14:11

1 Respuestas

No sé la forma correcta de manejar esta situación. Sin embargo, lo siguiente parece funcionar para mí en iOS 5.

  1. In splitViewController:willHideViewController:withBarButtonItem:forPopoverController:, almacene una referencia al barButtonItem en algo como self.barButtonItem. Mueva el código para mostrar el botón en un método separado, digamos ShowRootPopoverButtonItem.

  2. In splitViewController:willShowViewController:invalidatingBarButtonItem:, Limpia eso self.barButtonItem referencia hacia fuera. Mueva el código para mostrar el botón en un método separado, digamos InvalidateRootPopoverButtonItem.

  3. In viewWillLayoutSubviews, mostrar u ocultar manualmente el botón, según la orientación de la interfaz

Aquí está mi implementación de viewWillLayoutSubviews. Tenga en cuenta que llamando self.interfaceOrientation siempre devolvía el retrato, de ahí mi uso de statusBarOrientation.

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

respondido 09 nov., 11:09

Hola Noah, gracias por la solución, a mí también me está funcionando. Es un poco desafortunado porque viewWillLayoutSubviews se llama mucho más a menudo que los eventos de rotación, por lo que abarrotar todos los botones que ocultan / muestran la lógica significa que se ejecuta con mucha más frecuencia, pero parece que esta es la forma de hacer iOS5. estas cosas ahora. - Glenc

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.