2014-12-18 16 views
6

ho un UIViewlayout automatico e AVCaptureVideoPreviewLayer

@property (nonatomic, strong) IBOutlet UIView *previewView; 

previewView in ultima analisi, visualizzare l'anteprima di quello che sta succedendo nella mia macchina fotografica sul mio iPhone utilizzando il seguente strato di anteprima.

@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; 

devo vincoli impostati sul mio previewView in storyboard e quindi sono in esecuzione nel seguente problema.

self.previewLayer.frame = self.previewView.bounds; // This doesn't work 
self.previewLayer.videoGravity = AVLayerVideoGravityResize; 
[self.previewView.layer addSublayer:self.previewLayer]; 

previewLayer viene aggiunto al previewView sottolivello, ma non mostra nei giusti parametri (larghezza e altezza). Penso che questo sia dovuto all'utilizzo di vincoli sull'autolayout.

Come risolverei questo?

Update: Ho anche provato la seguente:

self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspect; 
CALayer *rootLayer = [previewView layer]; 
rootLayer.frame = self.previewView.bounds; 
[rootLayer setMasksToBounds:YES]; 
[self.previewLayer setFrame:[rootLayer bounds]]; 
[rootLayer addSublayer:self.previewLayer]; 

e sembra mostrare come questo: http://cl.ly/image/3T3o0O1E3U17

Come arrivare vicino, ma ancora molto al largo.

+0

Ho un problema simile. La mia immagine della fotocamera è molto simile alla tua, cioè c'è una grande barra vuota sul lato destro. Finora, ho capito che questo problema si verifica solo per me quando si utilizza Auto-Layout. – robert

risposta

10

Ok, l'ho risolto.

Il problema è che quando si utilizza layout automatico, i fotogrammi/limiti della subviews l' tuoi UIViewController può cambiare dopo aver impostato il tuo previewLayer, senza la previewLayer in sé di essere aggiornati di conseguenza! Questo perché il layout di CALayer s è esclusivamente controllato dal proprio codice (vedere anche questa risposta correlata: https://stackoverflow.com/a/27735617/623685).

Per risolvere questo problema, è necessario eseguire l'override del metodo del UIViewControllerviewDidLayoutSubviews per aggiornare 'la posizione s e limiti (e forse altri) ogni volta che il subviews' il previewLayer di layout modifiche.


In seguito, mi limiterò a descrivere come ho risolto in dettaglio:

Il mio caso era in realtà un po 'più complicato, perché sto utilizzando il framework OpenCV iOS 2.4.9. Qui, il livello di anteprima viene creato e gestito da una classe OpenCV denominata CvVideoCamera. Quindi ho dovuto creare una sottoclasse di CvVideoCamera, a cui ho aggiunto il seguente metodo:

- (void)updatePreviewLayer 
{ 
    self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); 
    [self layoutPreviewLayer]; 
} 

Spiegazione: parentView è un UIView si passa a CvVideoCamera al fine di specificare dove lo strato di anteprima deve essere posizionato e quanto grande dovrebbe essere. customPreviewLayer è il livello di anteprima gestito da CvVideoCamera. E layoutPreviewLayer è un metodo che aggiorna in sostanza la posizione del livello: https://github.com/Itseez/opencv/blob/2.4/modules/highgui/src/cap_ios_video_camera.mm#L211

Poi ho semplicemente chiamato questo metodo dal mio UIViewController in questo modo:

- (void)viewDidLayoutSubviews 
{ 
    NSLog(@"viewDidLayoutSubviews"); 
    [super viewDidLayoutSubviews]; 
    [self.myCameraView updatePreviewLayer]; 
} 
+0

ha funzionato perfettamente :) –

1

L'idea principale è lo stesso - quando si utilizza Autolayout, la cornice di il livello di anteprima deve essere impostato dopo aver applicato tutti i vincoli di visualizzazione.Il metodo viewDidLayoutSubviews viene utilizzato per questo, come nella risposta originale, ma senza complicazioni nell'utilizzo di framework diversi da quelli di Apple AVFoundation.

Il seguente codice è basato su un campione di Apple (AVCam-iOS: Using AVFoundation to Capture Images and Movies). Ma il codice è stato modificato per utilizzare il metodo updateViewConstraints per impostare a livello di codice tutti i vincoli anziché l'approccio Storyboard utilizzato nell'esempio. I frammenti rilevanti sono mostrati di seguito:

@interface QRScannerViewController() 

@property (nonatomic) UIView *previewView; 

@end 

@implementation QRScannerViewController 
{ 
    AVCaptureSession *_captureSession; 
    AVCaptureVideoPreviewLayer *_captureVideoPreviewLayer; 
    dispatch_queue_t _sessionQueue; 
} 

#pragma mark - Lifecycle 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self.view addSubview:self.previewView]; 

    _captureSession = [AVCaptureSession new]; 
    _captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_captureSession]; 
    _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 

    _sessionQueue = dispatch_queue_create("av_session_queue", DISPATCH_QUEUE_SERIAL); 

    [self.view setNeedsUpdateConstraints]; 

    dispatch_async(_sessionQueue, ^{ 
     [self configureCaptureSession]; 
    }); 

    [self.previewView.layer addSublayer:_captureVideoPreviewLayer]; 
} 

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    if (_isCaptureDeviceConfigured) { 
     [_captureSession startRunning]; 
    } 
} 

- (void)viewDidLayoutSubviews 
{ 
    _captureVideoPreviewLayer.frame = self.previewView.bounds; 
} 

#pragma mark - getters/initializers 

- (UIView *)previewView 
{ 
    if (_previewView) { 
     return _previewView; 
    } 
    _previewView = [UIView new]; 
    _previewView.backgroundColor = [UIColor blackColor]; 
    _previewView.translatesAutoresizingMaskIntoConstraints = NO; 

    return _previewView; 
} 

- (void)configureCaptureSession 
{ 
    [_captureSession beginConfiguration]; 

    // Code omitted, only relevant to the preview layer is included. See the Apple's sample for full code. 
    ... 
    _captureVideoPreviewLayer.connection.videoOrientation = initialVideoOrientation; 
    ... 
} 

#pragma mark - Autolayout 

- (void)updateViewConstraints 
{ 
    [self.previewView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor constant:0.0].active = YES; 
    [self.previewView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-40.0].active = YES; 
    [self.previewView.widthAnchor constraintEqualToConstant:300].active = YES; 
    [self.previewView.heightAnchor constraintEqualToAnchor:self.previewView.widthAnchor constant:0.0].active = YES; 

    [super updateViewConstraints]; 
} 
Problemi correlati