我正在使用avfoundation制作一个录音应用程序,我的肖像效果很好,但每当我旋转时,预览也会旋转(当我的手机从肖像向右向右旋转时,“v”变成了“<').
”我尝试使用 UIViewController 和 UIViewControllerRepresentable,我尝试将 updatePreviewLayerOrientation() 放在 viewDidLoad()、viewDidLayoutSubviews()、viewWillTransition() 中,但它们都不起作用。预览旋转并放大(我认为是由于resizeAspectFill)
class VideoPreviewView: UIView {
override class var layerClass: AnyClass {
return AVCaptureVideoPreviewLayer.self
}
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}
}
class CameraViewController: UIViewController {
private var previewView = VideoPreviewView()
override func viewDidLoad() {
super.viewDidLoad()
previewView.videoPreviewLayer.session = CameraManager.shared.session
previewView.videoPreviewLayer.videoGravity = .resizeAspectFill
previewView.videoPreviewLayer.frame = view.bounds
view.layer.addSublayer(previewView.videoPreviewLayer)
updatePreviewLayerOrientation
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
func updatePreviewLayerOrientation() {
guard let connection = previewView.videoPreviewLayer.connection else { return }
switch UIDevice.current.orientation {
case .portrait:
connection.videoOrientation = .portrait
case .landscapeRight:
connection.videoOrientation = .landscapeLeft
case .landscapeLeft:
connection.videoOrientation = .landscapeRight
case .portraitUpsideDown:
connection.videoOrientation = .portraitUpsideDown
default:
connection.videoOrientation = .portrait
}
previewView.videoPreviewLayer.frame = view.bounds
}
然后我改为 UIViewRepresentable。我再次尝试在 updateUIView 中调用 updatePreviewLayerOrientation() ,但在 updateUIView 中不起作用。
struct CameraViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> VideoPreviewView {
let view = VideoPreviewView()
view.backgroundColor = .black
view.videoPreviewLayer.session = CameraManager.shared.session
view.videoPreviewLayer.videoGravity = .resizeAspectFill
CameraManager.shared.videoPreview = view
return view
}
public func updateUIView(_ uiView: VideoPreviewView, context: Context) { }
class VideoPreviewView: UIView {
override class var layerClass: AnyClass {
AVCaptureVideoPreviewLayer.self
}
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}
}
}
我尝试编写一个 deideRotationModifier 并在那里更新方向,但不起作用。
struct DeviceRotationViewModifier: ViewModifier {
let action: (UIDeviceOrientation) -> Void
func body(content: Content) -> some View {
content
.onAppear()
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
action(UIDevice.current.orientation)
}
}
}
// A View wrapper to make the modifier easier to use
extension View {
func onRotate(perform action: @escaping (UIDeviceOrientation) -> Void) -> some View {
self.modifier(DeviceRotationViewModifier(action: action))
}
}
设置方向的正确方法是什么?
我得到答案了!!!
class VideoPreviewView: UIView {
override class var layerClass: AnyClass {
return AVCaptureVideoPreviewLayer.self
}
/// Convenience wrapper to get layer as its statically known type.
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}
}
class CameraViewController: UIViewController {
private var previewView = VideoPreviewView()
override func viewDidLoad() {
super.viewDidLoad()
let screenRect = UIScreen.main.bounds
previewView.videoPreviewLayer.session = CameraManager.shared.session
previewView.videoPreviewLayer.videoGravity = .resizeAspectFill
previewView.videoPreviewLayer.frame = CGRect(x: 0, y: 0, width: screenRect.size.width, height: screenRect.size.height)
previewView.videoPreviewLayer.connection?.videoOrientation = .portrait
view.layer.addSublayer(previewView.videoPreviewLayer)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: any UIViewControllerTransitionCoordinator) {
let screenRect = UIScreen.main.bounds
previewView.videoPreviewLayer.frame = CGRect(x: 0, y: 0, width: screenRect.size.width, height: screenRect.size.height)
updatePreviewLayerOrientation()
}
func updatePreviewLayerOrientation() {
guard let connection = previewView.videoPreviewLayer.connection else { return }
switch UIDevice.current.orientation {
case .portrait:
connection.videoOrientation = .portrait
case .landscapeRight:
connection.videoOrientation = .landscapeLeft
case .landscapeLeft:
connection.videoOrientation = .landscapeRight
case .portraitUpsideDown:
connection.videoOrientation = .portraitUpsideDown
default:
connection.videoOrientation = .portrait
}
}
}