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 |