2012-06-18 36 views
7

Ứng dụng của tôi hỗ trợ tất cả các hướng ngoại trừ PortraitUpsideDown. Trong phân cấp chế độ xem của tôi, tôi có AVCaptureVideoPreviewLayer làm lớp con trong chế độ xem trên cùng là UIImageView. Sau đó, bên dưới nó trong phân cấp khung nhìn là một số chế độ xem lớp phủ hiển thị các điều khiển.Làm thế nào để xử lý autorotation trong AVCaptureVideoPreviewLayer?

Chế độ xem lớp phủ đang hoạt động bình thường với các thay đổi định hướng, nhưng tôi không làm cách nào với AVCaptureVideoPreviewLayer này. Tôi muốn nó hoạt động giống như trong ứng dụng Máy ảnh, vì vậy previewLayer vẫn giữ nguyên và các điều khiển được tổ chức lại một cách suôn sẻ. Ngay bây giờ, khi chế độ xem chính được xoay theo hướng thay đổi, lớp xem trước của tôi cũng được xoay, có nghĩa là ở chế độ xem ngang, nó vẫn ở chế độ xem dọc, chỉ lấy một phần của màn hình và ảnh từ máy ảnh cũng được xoay 90 độ. Tôi đã xoay xở để xoay lớp xem trước theo cách thủ công, nhưng sau đó nó có hoạt ảnh thay đổi định hướng này, dẫn đến nền được nhìn thấy trong một thời gian trong khi hoạt ảnh.

Vì vậy, cách thích hợp để tự động kiểm soát các điều khiển trong khi thực hiện previewLayer vẫn là gì?

+1

Có vấn đề tương tự. Một giải pháp _obvious_ đáng buồn là không có sẵn: tôi đã hy vọng quan sát (với KVO) 'transform' của lớp 'presentationLayer' của khung nhìn mà không may mắn - key-value-observing không có sẵn trong thời gian chạy animation. Kết thúc bằng cách sử dụng (có thể) cùng một giải pháp như bạn: nhúng lớp xem trước vào một 'UIView' một cách thủ công xoay nó. –

+2

Vâng, tôi cũng đã kết thúc bằng cách xoay thủ công chế độ xem có chứa previewLayer. Hóa ra là không phức tạp lắm. Tôi áp dụng CGAffineTransformMakeRotation() và sau đó thay đổi khung thành kích thước chính xác. Nhưng bây giờ tôi có chính xác hành vi tôi muốn. – BartoNaz

+0

@BartoNaz Tôi đã đấu tranh với điều này trong một vài ngày nay và mọi thứ tôi cố gắng không cho tôi ảnh hưởng của camera.app nơi AVCaptureVideoPreviewLayer vẫn bị khóa vào chế độ xem và không xoay vòng hoạt ảnh. Bạn có thể vui lòng cung cấp đoạn mã làm việc của bạn như là một câu trả lời cho câu hỏi này? Cảm ơn. –

Trả lời

5

Trong triển khai của tôi, tôi đã phân lớp UIView cho chế độ xem mà tôi muốn xoay và một cái gì đó như viewController cho chế độ xem này, đây chỉ là lớp con của NSObject.

Trong giao diện nàyController Tôi thực hiện tất cả các kiểm tra liên quan đến thay đổi định hướng, quyết định xem có nên thay đổi hướng của chế độ xem mục tiêu hay không, và nếu có thì tôi gọi phương thức của tôi để thay đổi hướng của nó.

Trước hết, chúng tôi cần sửa định hướng của giao diện ứng dụng toàn bộ sang chế độ Chân dung, để ACCaptureVideoPreviewLayer của chúng tôi luôn ở trạng thái tĩnh. này được thực hiện trong MainViewController.h:

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

Nó trả NO cho tất cả các hướng trừ Portrait.

Để tùy chỉnh của chúng tôi viewController có thể theo dõi những thay đổi của hướng thiết bị chúng ta cần phải làm cho nó một người quan sát thông báo tương ứng:

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

tôi đặt những dòng này trong phương pháp (void)awakeFromNib của viewController tôi. Vì vậy, mỗi lần định hướng thiết bị được thay đổi, phương thức của viewController orientationChanged sẽ được gọi.

Mục đích của nó là kiểm tra định hướng mới của thiết bị là gì, định hướng cuối cùng của thiết bị và quyết định xem có thay đổi thiết bị hay không. Đây là triển khai:

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

Nếu định hướng giống như trước hoặc trong PortraitUpsideDown thì không làm gì cả. Khác nó đặt hướng thanh trạng thái thành một hướng thích hợp, để khi có cuộc gọi đến hoặc sự hiện diện hóa, nó sẽ xuất hiện ở phía bên phải của màn hình. Và sau đó tôi cũng gọi phương thức ở chế độ xem đích nơi tất cả các thay đổi tương ứng cho hướng mới được thực hiện, như xoay, thay đổi kích thước, di chuyển các phần tử giao diện khác trong chế độ xem này tương ứng với hướng mới.

Đây là việc thực hiện các orientationChanged theo quan điểm mục tiêu:

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

Tất nhiên ở đây bạn có thể thêm bất kỳ thay đổi khác như dịch thuật, mở rộng quy mô các quan điểm khác nhau của giao diện của bạn cần phải đáp ứng với định hướng mới và animate chúng.

Ngoài ra, bạn có thể không cần viewController cho điều này, nhưng làm tất cả chỉ trong lớp của chế độ xem của bạn. Hy vọng rằng ý tưởng chung là rõ ràng.

Cũng đừng quên để ngừng nhận thông báo cho thay đổi hướng khi bạn không cần đến chúng thích:

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

Vấn đề chính là khi tôi nhận được thông báo, statusbar vẫn chưa xoay, do đó, kiểm tra giá trị hiện tại cung cấp cho thực tế giá trị trước khi xoay. Vì vậy, tôi đã thêm một chút chậm trễ (ở đây 2 giây) trước khi gọi phương thức kiểm tra trạng thái trạng thái và xoay tiểu sử của tôi:

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

Phần còn lại của mã là từ BartoNaz.

+0

Tôi không chắc chắn nếu điều này là chính xác. Đó chính xác là ý tưởng của phương pháp này, rằng thanh trạng thái không tự xoay. Và bạn không kiểm tra hướng hiện tại của thanh trạng thái. Bạn đang kiểm tra hướng của thiết bị và so sánh nó với hướng từ lần cuối cùng khi phương pháp này được gọi. Và khi phương thức của bạn quyết định thay đổi hướng, nó thực hiện thay đổi theo cách thủ công, bằng cách gọi '[[UIApplication sharedApplication] setStatusBarOrientation: [UIDevice currentDevice] .ororation animation: NO];' – BartoNaz

+0

Bạn nên sử dụng định hướng thiết bị thay vì định hướng thanh trạng thái tại đây . –

1

iOS 8 giải pháp:

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

trong mã thiết lập của bạ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; 
}