2012-06-18 9 views
7

Mi aplicación es compatible con todas las orientaciones excepto PortraitUpsideDown. En mi jerarquía de vistas, tengo una AVCaptureVideoPreviewLayer como una subcapa en la vista superior que es UIImageView. A continuación, debajo de la jerarquía de vista hay varias vistas de superposición que muestran los controles.¿Cómo manejar la autorrotación en AVCaptureVideoPreviewLayer?

Las vistas de superposición funcionan correctamente con cambios de orientación, pero no sé cómo estar con esta AVCaptureVideoPreviewLayer. Quiero que se comporte como en la aplicación de la cámara, de modo que la vista previa permanezca inmóvil y los controles se reorganicen sin problemas. Ahora que la vista principal gira en el cambio de orientación, mi capa de vista previa también se gira, lo que significa que en la vista horizontal permanece en la vista vertical, tomando solo una parte de la pantalla y la imagen de la cámara también girada 90 grados. Pude rotar la capa de vista previa manualmente, pero luego tiene esta animación de cambio de orientación, lo que hace que el fondo se vea durante un momento durante la animación.

¿Cuál es la forma correcta de autorrotar los controles mientras se hace la vista previa?

+1

Tenía un problema similar. Desafortunadamente, una solución _obvious_ no está disponible: esperaba observar (con KVO) 'transformar' del' presentationLayer' de la capa de visualización sin suerte - la observación de clave-valor no está disponible durante el tiempo de ejecución de la animación. Terminó usando (probablemente) la misma solución que usted: incrustando la capa de vista previa en un 'UIView' y haciéndola girar manualmente. –

+2

Sí, también terminé con la rotación manual de la vista que contiene la vista previa. Resultó que no era muy complicado. Aplico CGAffineTransformMakeRotation() y luego cambio el marco al tamaño correcto. Pero ahora tengo exactamente el comportamiento que quiero. – BartoNaz

+0

@BartoNaz He estado luchando con esto por un par de días y todo lo que intento no me da el efecto de la cámara. Aplicación donde AVCaptureVideoPreviewLayer permanece bloqueado a una vista, y no hace su rotación animada. ¿Podría proporcionarnos su fragmento de código de trabajo como respuesta a esta pregunta? Gracias. –

Respuesta

5

En mi implementación he subclasificado el UIView para mi vista que quiero rotar y algo así como viewController para esta vista que es solo una subclase de NSObject.

En este viewController realizo todas las comprobaciones relacionadas con los cambios de orientación, tomo la decisión si debo cambiar la orientación de mi vista objetivo, y si es así, entonces llamo al método de mi vista para cambiar su orientación.

En primer lugar, debemos corregir la orientación de toda la interfaz de la aplicación al modo vertical, de modo que nuestra captura de pantalla ACCaptureVideoPreview permanezca siempre fija. Esto se hace en el MainViewController.h:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation` 
{ 
    return interfaceOrientation==UIInterfaceOrientationPortrait; 
} 

Devuelve NO a todas las orientaciones, excepto retrato.

Con el fin de nuestra costumbre viewController ser capaz de seguir los cambios de orientación del dispositivo que necesitamos para que sea un observador de las notificaciones correspondientes:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil]; 

pongo estas líneas en el método de mi viewController (void)awakeFromNib. Entonces, cada vez que se cambia la orientación del dispositivo, se llamará al método viewcontroller orientationChanged.

Su propósito es comprobar cuál es la nueva orientación del dispositivo, cuál fue la última orientación del dispositivo y decidir si cambiarlo. Aquí está la aplicación:

if(UIInterfaceOrientationPortraitUpsideDown==[UIDevice currentDevice].orientation || 
    lastOrientation==(UIInterfaceOrientation)[UIDevice currentDevice].orientation) 
    return; 
    [[UIApplication sharedApplication]setStatusBarOrientation:[UIDevice currentDevice].orientation animated:NO]; 

    lastOrientation=[UIApplication sharedApplication].statusBarOrientation; 
    [resultView orientationChanged]; 

Si la orientación es la misma que antes o en PortraitUpsideDown luego no hacer nada. De lo contrario, establece la orientación de la barra de estado en la correcta, de modo que cuando haya una llamada entrante u osificación, aparecerá en el lado correcto de la pantalla. Y luego invoco también el método en la vista de destino donde se realizan todos los cambios correspondientes para la nueva orientación, como rotar, redimensionar, mover los otros elementos de la interfaz en esta vista correspondiente a la nueva orientación.

Aquí es la aplicación de la orientationChanged en vista de destino:

Float32 angle=0.f; 
UIInterfaceOrientation orientation=[UIApplication sharedApplication].statusBarOrientation; 

switch (orientation) { 
    case UIInterfaceOrientationLandscapeLeft: 
     angle=-90.f*M_PI/180.f; 
     break; 
    case UIInterfaceOrientationLandscapeRight: 
      angle=90.f*M_PI/180.f; 
     break; 
    default: angle=0.f; 
     break; 
} 
if(angle==0 && CGAffineTransformIsIdentity(self.transform)) return; 

CGAffineTransform transform=CGAffineTransformMakeRotation(angle); 

[UIView beginAnimations:@"rotateView" context:nil]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 
[UIView setAnimationDuration:0.35f]; 

self.transform=transform; 

[UIView commitAnimations]; 

Por supuesto, aquí se puede añadir cualquier otro cambio como la traducción, la escala de las diferentes vistas de su interfaz que necesitan para responder a la nueva orientación y animar ellos.

También puede que no necesite el control de vista para esto, pero haga todo solo en la clase de su vista. Espero que la idea general sea clara.

Tampoco se olvide de dejar de recibir la notificación de los cambios de orientación cuando no los necesita como:

[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 
[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications]; 
0

El principal problema es que cuando llegue la notificación, la barra de estado aún no ha girado, de modo que al verificar el valor actual se obtiene el valor antes de la rotación. Por lo que añade un poco de retraso (en este caso 2 segundos) antes de llamar al método que comprueba la statusbarorientation y gira mi subvista:

-(void) handleNotification:(NSNotification *) notification 
{  
    (void) [NSTimer scheduledTimerWithTimeInterval:(2.0) 
              target:self 
              selector:@selector(orientationChanged) 
              userInfo:nil 
              repeats:NO ] ; 
} 

El resto del código es el de BartoNaz.

+0

No estoy seguro de si esto es correcto. Esa es exactamente la idea de este método, que la barra de estado no gira por sí misma. Y no verifica la orientación actual de la barra de estado. Está comprobando la orientación del dispositivo y lo compara con la orientación de la última vez que se llamó este método. Y cuando su método decide cambiar la orientación, lo hace manualmente, llamando a '[[UIApplication sharedApplication] setStatusBarOrientation: [UIDevice currentDevice] .orientation animated: NO];' – BartoNaz

+0

Debe usar la orientación del dispositivo en lugar de la orientación de la barra de estado aquí . –

1

iOS 8 solución:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { 
    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { 
     self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft; 
    } else { 
     self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; 
    } 
} 

en su código de configuración:

self.layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; 
self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { 
    self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft; 
} else { 
    self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; 
} 
Cuestiones relacionadas