Preventing AVCaptureVideoPreviewLayer from rotating, but allow UI layer to rotate with orientation

对着背影说爱祢 提交于 2019-11-29 02:34:40

Make sure to set shouldAutorotate to return false:

-(BOOL)shouldAutorotate{
    return NO;
}

register for Notifications that orientation changed:

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

implement the notification change

-(void)orientationChanged:(NSNotification *)notif {
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];

// Calculate rotation angle
CGFloat angle;
switch (deviceOrientation) {
    case UIDeviceOrientationPortraitUpsideDown:
        angle = M_PI;
        break;
    case UIDeviceOrientationLandscapeLeft:
        angle = M_PI_2;
        break;
    case UIDeviceOrientationLandscapeRight:
        angle = - M_PI_2;
        break;
    default:
        angle = 0;
        break;
}


}

and rotate the UI

 [UIView animateWithDuration:.3 animations:^{
        self.closeButton.transform = CGAffineTransformMakeRotation(angle);
        self.gridButton.transform = CGAffineTransformMakeRotation(angle);
        self.flashButton.transform = CGAffineTransformMakeRotation(angle);
    } completion:^(BOOL finished) {

}];

This is how I implement the screen being locked but rotating the UI, if this works link the stacks post and I can copy it over there and you can tick it :P

I have a very similar situation. I just have one view controller and I want to have a AVCaptureVideoPreviewLayer that doesn't rotate in it. I found the accepted solution by @SeanLintern88 did not work for me; the status bar never moved and the WKWebView I had on the screen was not getting resizes properly.

One of the bigger issues I ran into was that I was putting my AVCaptureVideoPreviewLayer in the view controller's view. It is much better to create a new UIView just to hold the layer.

After that I found a technical note from Apple QA1890: Preventing a View From Rotating. This allowed me to produce the following swift code:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    coordinator.animateAlongsideTransition(
        { (UIViewControllerTransitionCoordinatorContext) in
            let deltaTransform = coordinator.targetTransform()
            let deltaAngle = atan2f(Float(deltaTransform.b), Float(deltaTransform.a))
            var currentRotation : Float = (self.previewView!.layer.valueForKeyPath("transform.rotation.z")?.floatValue)!
            // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
            currentRotation += -1 * deltaAngle + 0.0001;
            self.previewView!.layer.setValue(currentRotation, forKeyPath: "transform.rotation.z")
            self.previewView!.layer.frame = self.view.bounds
        },
        completion:
        { (UIViewControllerTransitionCoordinatorContext) in
            // Integralize the transform to undo the extra 0.0001 added to the rotation angle.
            var currentTransform : CGAffineTransform = self.previewView!.transform
            currentTransform.a = round(currentTransform.a)
            currentTransform.b = round(currentTransform.b)
            currentTransform.c = round(currentTransform.c)
            currentTransform.d = round(currentTransform.d)
            self.previewView!.transform = currentTransform
        })
}

The original tech note did not have the line self.previewView!.layer.frame = self.view.bounds but I found that very necessary because although the anchor point doesn't move, the frame has. Without that line, the preview will be offset.

Also, since I am doing all of the work keeping the view in the correct position, I had to remove all the positioning constraints on it. When I had them in, they would cause the preview to instead be offset in the opposite direction.

On the view that shows the camera output add:

AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
if ([layer.connection isVideoOrientationSupported]) {
    [layer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
  }

AVCaptureVideoOrientationPortrait is just one option. You can choose from the following:

typedef NS_ENUM(NSInteger, AVCaptureVideoOrientation) {
    AVCaptureVideoOrientationPortrait           = 1,
    AVCaptureVideoOrientationPortraitUpsideDown = 2,
    AVCaptureVideoOrientationLandscapeRight     = 3,
    AVCaptureVideoOrientationLandscapeLeft      = 4,
}

This must be done after you setup the session.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!