UIViewRepresentable은 하나의 뷰를 다룬다면 UIViewControllerRepresentable은 그 뷰들을 담는 컨트롤러를 의미합니다

 

UIViewControllerRepresentable 이란

UIViewControollerRepresentable이란 UIKit을 기반으로 SwiftUI에서 사용할 수 있게 끔 또는 SwiftUI기반으로 UIkit에서 사용할 수 있게 끔 만들어주는 프로토콜입니다.

 

사용하기위한 기초 작업

UIViewControllerRepresentable을 사용하기 위해서는 우선 다음 두 메서드를 정의해야합니다.

 makeUIViewController 메서드는 SwiftUI 기반의 코드를 UIKit으로 만들기 위한 메서드

updateUIViewcontroller 메서드는 SwiftUI에 UIKit 기반 코드에서 변경되는 데이터를 반영하기 위해서 사용되는 메서드입니다.

 

func makeUIViewController(context: Context) -> some UIViewController {

}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

}

 

간단한 작업

다음으로는 버튼을 눌렀을 때 UIViewControllerRepresentable 를 사용하여 UIKit으로 만든 기반의 viewController를 화면에 띄우는 코드입니다.

struct ContentView: View {
    
    @State private var showScreen: Bool = false
    
    var body: some View {
        VStack {
            Button {
                showScreen.toggle()
            } label: {
                Text("클릭하기")
            }
            .sheet(isPresented: $showScreen, content: {
                BasicUIViewControllerRepresentable(labelText: "새로운 글")
            })

        }
        .padding()
    }
}

 

UIKit을 사용하여 UIViewController를 만든 다음 구성한 다음 해당 뷰를 반환하면 됩니다. 

struct BasicUIViewControllerRepresentable: UIViewControllerRepresentable {
    
    let labelText: String
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let vc = UIViewController()
        vc.view.backgroundColor = .blue
        
        let label = UILabel()
        label.text = labelText
        label.textColor = UIColor.white
        
        vc.view.addSubview(label)
        label.frame = vc.view.frame
        
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

 

위에 코드를 좀 더 직관적으로 보기 쉽게 만들기 위해서는 새로운 UIViewController 프로토콜을 준수하는 컨트롤러를 만들어 해당 뷰에 컨포넌트들을 구성한 후 사용하면 좀 더 깔끔해집니다.

struct BasicUIViewControllerRepresentable: UIViewControllerRepresentable {
    
    let labelText: String
    
    func makeUIViewController(context: Context) -> some UIViewController {
        return MyFirstViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

class MyFirstViewController: UIViewController {
    
    let labelText: String = "Default value"

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .blue
        
        let label = UILabel()
        label.text = labelText
        label.textColor = UIColor.white
        
        view.addSubview(label)
        label.frame = view.frame
    }
}

 

 

 

 

SwiftUI를 사용하여 UIImagePickerController를 사용하여 사진을 가져오는 코드는 현재는 SwiftUI에서 제공되지만 그러지 않았던 시절이 있습니다. 이런 상황에서 UIViewControllerRepresentable 프로토콜을 사용하는 것입니다.

 

makeCoordinator를 사용하여 UIKit으로 구현한 코드에서 변경된 사항이 SwiftUI에 적용되게 만들 수 있습니다.

struct ContentView: View {
    
    @State private var showScreen: Bool = false
    @State private var image: UIImage? = nil
    
    var body: some View {
        VStack {
            
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200)
            }
            Button {
                showScreen.toggle()
            } label: {
                Text("클릭하기")
            }
            .sheet(isPresented: $showScreen, content: {
                UIImagePickerControllerRepresentable(image: $image, showScreen: $showScreen)
            })

        }
        .padding()
    }
}

#Preview {
    ContentView()
}

struct UIImagePickerControllerRepresentable: UIViewControllerRepresentable {
    
    @Binding var image: UIImage?
    @Binding var showScreen: Bool
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let vc = UIImagePickerController()
        vc.allowsEditing = false
        vc.delegate = context.coordinator
        return vc
    }
    
    // SwiftUI에서 UIKit으로
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
    
    // UIKit에서 SwiftUI로
    func makeCoordinator() -> Coordinator {
        return Coordinator(image: $image, showScreen: $showScreen)
    }
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        @Binding var image: UIImage?
        @Binding var showScreen: Bool

        init(image: Binding<UIImage?>, showScreen: Binding<Bool>) {
            self._image = image
            self._showScreen = showScreen
        }
        
        // 이미지를 선택할 때 실행되는 콜백함수
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            guard let newImage = info[.originalImage] as? UIImage else { return }
            image = newImage
            showScreen = false
        }
        
    }
}

 

전체 코드

import SwiftUI

struct ContentView: View {
    
    @State private var showScreen: Bool = false
    @State private var image: UIImage? = nil
    
    var body: some View {
        VStack {
            
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200)
            }
            Button {
                showScreen.toggle()
            } label: {
                Text("클릭하기")
            }
            .sheet(isPresented: $showScreen, content: {
//                BasicUIViewControllerRepresentable(labelText: "새로운 글")
                UIImagePickerControllerRepresentable(image: $image, showScreen: $showScreen)
            })

        }
        .padding()
    }
}

#Preview {
    ContentView()
}

struct UIImagePickerControllerRepresentable: UIViewControllerRepresentable {
    
    @Binding var image: UIImage?
    @Binding var showScreen: Bool
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let vc = UIImagePickerController()
        vc.allowsEditing = false
        vc.delegate = context.coordinator
        return vc
    }
    
    // SwiftUI에서 UIKit으로
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
    
    // UIKit에서 SwiftUI로
    func makeCoordinator() -> Coordinator {
        return Coordinator(image: $image, showScreen: $showScreen)
    }
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        @Binding var image: UIImage?
        @Binding var showScreen: Bool

        init(image: Binding<UIImage?>, showScreen: Binding<Bool>) {
            self._image = image
            self._showScreen = showScreen
        }
        
        // 이미지를 선택할 때 실행되는 콜백함수
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            guard let newImage = info[.originalImage] as? UIImage else { return }
            image = newImage
            showScreen = false
        }
        
    }
}

struct BasicUIViewControllerRepresentable: UIViewControllerRepresentable {
    
    let labelText: String
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let vc = MyFirstViewController()
        vc.labelText = labelText
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

class MyFirstViewController: UIViewController {
    
    var labelText: String = "Default value"

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .blue
        
        let label = UILabel()
        label.text = labelText
        label.textColor = UIColor.white
        
        view.addSubview(label)
        label.frame = view.frame
    }
}

 

 

'SwiftUI' 카테고리의 다른 글

KaKao Map 카카오맵  (0) 2024.04.30
Protocols 프로토콜  (0) 2024.04.27
PreferenceKey  (0) 2024.04.25
UIViewRepresentable SwiftUI에서 UIKit 사용하기  (0) 2024.04.24
사용자한테 보여줄 색깔 선택하기  (0) 2024.04.23
ytw_developer