Avoiding rotation of AVCaptureVideoPreviewLayer, but allowing orientation rotation of the UI layer

I have two view controllers. One of them is the root of the VC and contains a user interface interface such as a record button. On this view controller, I also show the view of another VC with index 0. This view contains AVCaptureVideoPreviewLayer.

I would like my camcorder to mimic an Apple camcorder application where the layout of the interface is adjusted by rotation, but the video preview level does not work. You can see how the recording timer (UILabel) in the video surveillance application disappears and appears at the top depending on the orientation.

Any ideas how to do this? I found one suggestion that it is recommended to add a preview to the application delegate window, since it will not correspond to the rotation of the navigation controller, but this did not work for me.

Thank!

+5
source share
4 answers

Be sure to set the shouldAutorotate parameter to false:

-(BOOL)shouldAutorotate{
    return NO;
}

register to be notified that the orientation has changed:

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

change notification

-(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 turn 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 lock, but rotating the user interface, if that works, binds the stack post, and I can copy it there, and you can mark it: P

+6
source

. , AVCaptureVideoPreviewLayer, . , @SeanLintern88 ; , WKWebView, , .

, , , AVCaptureVideoPreviewLayer . UIView .

Apple QA1890: . :

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
        })
}

self.previewView!.layer.frame = self.view.bounds, , , , . .

, , , . , .

+9

, , :

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

AVCaptureVideoOrientationPortrait - . :

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

, .

+1

, "" .

, , , AVCaptureVideoPreviewLayer , metadataOutputRectConverted(fromLayerRect:).

, QA1890 " ", Swift 5 .

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        self.cameraPreviewView = UIView(frame: view.bounds)
        self.cameraPreviewView.layer.addSublayer(self.videoPreviewLayer)
        self.videoPreviewLayer.connection?.videoOrientation = UIApplication.shared.statusBarOrientation.asAVCaptureVideoOrientation()
        self.videoPreviewLayer.frame = self.cameraPreviewView.bounds
        self.view.addSubview(self.cameraPreviewView)
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        self.cameraPreviewView.center = self.view.bounds.midPoint
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        let cameraPreviewTransform = self.cameraPreviewView.transform

        coordinator.animate(alongsideTransition: { context in
            // Keep the camera preview view inversely rotatated with the rest of the view during transition animations
            let deltaTransform = coordinator.targetTransform
            let deltaAngle: CGFloat = atan2(deltaTransform.b, deltaTransform.a)

            var previewCurrentRotation = atan2(cameraPreviewTransform.b, cameraPreviewTransform.a)

            // 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.
            previewCurrentRotation += -1 * deltaAngle + 0.0001
            self.cameraPreviewView.layer.setValue(previewCurrentRotation, forKeyPath: "transform.rotation.z")
        }, completion: { context in
            // Now the view transition animations are complete, we will adjust videoPreviewLayer properties to fit the current orientation
            // Changing the frame of a videoPreviewLayer animates the resizing of the preview view, so we disable animations (actions) to remove this effect
            CATransaction.begin()
            CATransaction.setDisableActions(true)
            self.cameraPreviewView.transform = cameraPreviewTransform
            self.cameraPreviewView.frame = self.view.bounds

            self.videoPreviewLayer.connection?.videoOrientation = UIApplication.shared.statusBarOrientation.asAVCaptureVideoOrientation()
            self.videoPreviewLayer.frame = self.cameraPreviewView.bounds

            CATransaction.commit()
        })
    }

extension UIInterfaceOrientation {
    func asAVCaptureVideoOrientation() -> AVCaptureVideoOrientation {
        switch self {
        case .portrait:
            return .portrait
        case .landscapeLeft:
            return .landscapeLeft
        case .landscapeRight:
            return .landscapeRight
        case .portraitUpsideDown:
            return .portraitUpsideDown
        default:
            return .portrait
        }
    }
}
0

All Articles