【发布时间】:2020-06-16 13:52:25
【问题描述】:
我正在使用 SwiftUI 开发一个应用程序 - 使用一些 UIKit 组件 - 具有画中画功能,并且我试图在旋转设备时将图片保持在屏幕的特定角落。为此,我需要更改框架在视图上的位置,因此我已注册 UIDevice.orientationDidChangeNotification,当收到此通知时,我会更改 UIViewController 中的视图框架,如下所示:
@objc func onViewDidTransition() {
view.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
}
但是,这似乎没有任何作用。框架根本没有变化。好像UIView 保留了旧框架并更改为新的CGRect 无济于事。当我使用view.frame. 检查对象时,没有x 或y 的选项,好像这些属性在初始化后不可更改。这是正确的吗?我没有办法改变框架的位置吗?
编辑:代码。
框架在CustomCameraController的setup()函数中设置
func setup() {
view.frame = CGRect(x: 225, y: 0, width: 150, height: 150)
后来在onViewDidTransition()修改了
@objc func onViewDidTransition() {
view.frame = CGRect(x: 662, y: 0, width: 150, height: 150)
当转换为横向时,这应该将图片放在右上角 (iphone x),但事实并非如此。图像停留在距左角 200 pt 处。
最少可重现的 ContentView 代码
import SwiftUI
import AVFoundation
struct CustomCameraPhotoView: View {
@State private var image: Image?
@State private var showingCustomCamera = false
@State private var showImagePicker = false
@State private var inputImage: UIImage?
@State private var url: URL?
var body: some View {
CustomCameraView(image: self.$inputImage)
}
}
struct CustomCameraView: View {
@Binding var image: UIImage?
@State var didTapCapture: Bool = false
var body: some View {
ZStack() {
CustomCameraRepresentable(image: self.$image, didTapCapture: $didTapCapture)
}
}
}
struct CustomCameraRepresentable: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
@Binding var didTapCapture: Bool
func makeUIViewController(context: Context) -> CustomCameraController {
let controller = CustomCameraController()
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ cameraViewController: CustomCameraController, context: Context) {
if(self.didTapCapture) {
cameraViewController.didTapRecord()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, AVCapturePhotoCaptureDelegate {
let parent: CustomCameraRepresentable
init(_ parent: CustomCameraRepresentable) {
self.parent = parent
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
parent.didTapCapture = false
if let imageData = photo.fileDataRepresentation() {
parent.image = UIImage(data: imageData)
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
class CustomCameraController: UIViewController {
var image: UIImage?
var captureSession = AVCaptureSession()
var backCamera: AVCaptureDevice?
var frontCamera: AVCaptureDevice?
var currentCamera: AVCaptureDevice?
var photoOutput: AVCapturePhotoOutput?
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
//DELEGATE
var delegate: AVCapturePhotoCaptureDelegate?
func didTapRecord() {
let settings = AVCapturePhotoSettings()
photoOutput?.capturePhoto(with: settings, delegate: delegate!)
}
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() {
view.frame = CGRect(x: 225, y: 0, width: 150, height: 150)
view.layer.cornerRadius = 40
view.layer.masksToBounds = true
view.backgroundColor = .white
setupCaptureSession()
setupDevice()
setupInputOutput()
setupPreviewLayer()
startRunningCaptureSession()
NotificationCenter.default.addObserver(self, selector: #selector(onViewDidTransition), name: UIDevice.orientationDidChangeNotification, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}
@objc func onViewDidTransition() {
view.frame = CGRect(x: 662, y: 0, width: 150, height: 150)
self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
//UIDevice.current.orientation
}
func setupCaptureSession() {
let cameraMediaType = AVMediaType.video
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: cameraMediaType)
switch cameraAuthorizationStatus {
case .denied: break
case .authorized: break
case .restricted: break
case .notDetermined:
// Prompting user for the permission to use the camera.
AVCaptureDevice.requestAccess(for: cameraMediaType) { granted in
if granted {
print("Granted access to \(cameraMediaType)")
} else {
print("Denied access to \(cameraMediaType)")
}
}
@unknown default:
break
}
captureSession.sessionPreset = AVCaptureSession.Preset.iFrame1280x720
}
func setupDevice() {
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera],
mediaType: AVMediaType.video,
position: AVCaptureDevice.Position.front)
for device in deviceDiscoverySession.devices {
switch device.position {
case AVCaptureDevice.Position.front:
self.frontCamera = device
case AVCaptureDevice.Position.back:
self.backCamera = device
default:
break
}
}
self.currentCamera = self.frontCamera
}
func setupInputOutput() {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
captureSession.addInput(captureDeviceInput)
photoOutput = AVCapturePhotoOutput()
photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.hevc])], completionHandler: nil)
captureSession.addOutput(photoOutput!)
} catch {
print(error)
}
}
func setupPreviewLayer()
{
self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
self.cameraPreviewLayer?.cornerRadius = 40
self.cameraPreviewLayer?.masksToBounds = true
self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
self.cameraPreviewLayer?.frame = self.view.frame
self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}
func startRunningCaptureSession(){
captureSession.startRunning()
}
}
【问题讨论】:
-
任何最小的可重现代码?
-
@Asperi 我会准备一些东西并编辑我的问题
-
@Asperi 我添加了一些重点内容,应该可以用不多的代码证明问题。