将 UIViewRepresentable 连接到 SwiftUI

Posted

技术标签:

【中文标题】将 UIViewRepresentable 连接到 SwiftUI【英文标题】:Connect UIViewRepresentable to SwiftUI 【发布时间】:2022-01-18 22:22:18 【问题描述】:

我有一个基于 SwiftUI 的应用程序,带有一个简单的按钮,按下该按钮时应该会从 AVFoundation 打开一个也使用 UIKit 的相机类。在工作表下,我不确定该放什么。我尝试了 CameraSession() 和其他一些想法,但在桥接这个 SwiftUI 按钮以打开相机应用程序时我有点迷失了。谢谢!

//内容视图

import SwiftUI

struct ContentView: View 
    //@State private var image: Image?
    @State private var showingCameraSession = false
    //@Binding var isShown: Bool
    var body: some View 
        VStack
            
            ControlButton(systemIconName: "slider.horizontal.3")
            //Button("Seelect Image") 
                showingCameraSession = true
             .sheet(isPresented: $showingCameraSession)
            //What to place here?

                
            
           
       
    

//CameraSession

import AVFoundation
//import RealityKit
import UIKit
import SwiftUI



struct CameraSession : UIViewControllerRepresentable 
    //@Binding var isShown: Bool
    typealias UIViewControllerType = CaptureSession
    
    func makeUIViewController(context: Context) -> CaptureSession
        return CaptureSession()
    

    func updateUIViewController(_ uiViewController: CaptureSession, context: Context) 
           // if(self.isShown)
                //CameraSession.didTapTakePhoto()
               // shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
            
        





class CaptureSession: UIViewController 
    //@Binding var isShown: Bool
    
    
     //Reference: https://www.youtube.com/watch?v=ZYPNXLABf3c
    //CaptureSession
    var session: AVCaptureSession?
    //PhotoOutput  --> to the Cloud
    let output = AVCapturePhotoOutput()
    // Video Preview
    let previewLayer = AVCaptureVideoPreviewLayer()
    
    
    //Shutter Button
    
    private let shutterButton: UIButton = 
        let button = UIButton(frame: CGRect(x:0, y:0, width: 100, height: 100))
        button.layer.cornerRadius = 50
        button.layer.borderWidth = 10
        button.layer.borderColor = UIColor.white.cgColor
        return button
        
    ()
    
    
    override func viewDidLoad() 
        super.viewDidLoad()
        view.backgroundColor = .black
        //previewLayer.backgroundColor = UIColor.systemRed.cgColor
        view.layer.addSublayer(previewLayer)
        view.addSubview(shutterButton)
        checkCameraPermissions()
      
       shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
    
    
    override func viewDidLayoutSubviews()
        super.viewDidLayoutSubviews()
        previewLayer.frame = view.bounds
        
        shutterButton.center = CGPoint(x: view.frame.size.width/2, y: view.frame.size.height - 100)
    
    
    private func checkCameraPermissions() 
        switch AVCaptureDevice.authorizationStatus(for: .video)
            
        case .notDetermined:
            //Request Permission
            AVCaptureDevice.requestAccess(for: .video)  [weak self] granted in
                guard granted else 
                    return
                
                DispatchQueue.main.async
                    self?.setUpCamera()
                
            
        case .restricted:
            break
        case .denied:
            break
        case .authorized:
            setUpCamera()
        @unknown default:
            break
        
    
    //with Photogrammetry, you also have to create a session similar https://developer.apple.com/documentation/realitykit/creating_3d_objects_from_photographs/
    // example app: https://developer.apple.com/documentation/realitykit/taking_pictures_for_3d_object_capture
    private func setUpCamera()
        let session = AVCaptureSession()
        if let device = AVCaptureDevice.default(for: .video)
            do
                let input = try AVCaptureDeviceInput(device: device)
                if session.canAddInput(input)
                    session.addInput(input) //some Devices contract each other.
                
                if session.canAddOutput(output) 
                    session.addOutput(output)
                
                previewLayer.videoGravity = .resizeAspectFill //content does not get distored or filled
                previewLayer.session = session
                 
                
                session.startRunning()
                self.session = session
                
            
            catch
                print(error)
            
        
    
    //originally private
    @objc private func didTapTakePhoto() 
       
         output.capturePhoto(with: AVCapturePhotoSettings(),
                            delegate: self)
       // let vc = UIHostingController(rootView: ContentView())
       // present(vc, animated: true)
        
    

 //AVCaptureOutput is AVFoundations version of photo output
extension CaptureSession: AVCapturePhotoCaptureDelegate 
    func photoOutput( output: AVCaptureOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error:
                      Error?)
                      guard let data = photo.fileDataRepresentation() else  //where to store file information
                        return
                      
                    let image = UIImage(data: data)
        
        session?.stopRunning()
        
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFill
        imageView.frame = view.bounds
        view.addSubview(imageView)
    

【问题讨论】:

这应该会有所帮助***.com/a/59064305/12299030。 @Asperi 我在这个问题上已经有一段时间了。看来您链接的那个都在一个脚本中,我将 2 个单独的脚本链接在一起并且在激活相机时遇到问题。你提供的这个是一个单一的脚本——我确实弄乱了一些提供的代码,但不幸的是,进展仍然很小 【参考方案1】:

所以要解决这个问题,首先让您的应用有权访问用户相机(转到顶部构建设置旁边的 Info.plist 或信息选项卡并添加隐私相机使用情况并添加“我们需要您的相机来执行此操作行动”)

然后在工作表的修饰符中进行一个简单的调用就可以解决问题

struct ContentView: View 
    //@State private var image: Image?
    @State private var showingCameraSession = false
    //@Binding var isShown: Bool
    var body: some View 
        VStack
            
//            ControlButton(systemIconName: "slider.horizontal.3")
            Button("Seelect Image") 
                showingCameraSession = true
             .sheet(isPresented: $showingCameraSession)
            //What to place here?
                
                CameraSession()

                
            
           
       
    

【讨论】:

非常感谢!这解决了问题 如果回答有帮助请点赞

以上是关于将 UIViewRepresentable 连接到 SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章

将 UIViewRepresentable 用于自定义组件不起作用

SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View

UIViewRepresentable 自动大小 - 将 UIKit UIView 大小传递给 SwiftUI

SwiftUI 通过实现 UIViewRepresentable 来使用 UIKit 组件

无法将点击手势识别器添加到 SwiftUI MKMapView UIViewRepresentable

如何找到 SwiftUI UIViewRepresentable 的框架