UIViewController를 SwiftUI View에서 사용하는 법
UIViewController를 SwiftUI에서 사용할 수 있는 방법을 찾다가 나중에 까먹었을 때 다시 보려고 포스팅하려고 합니다 :)
UIViewController 는 SwiftUI 가 알아먹지 못하므로 SwiftUI 가 알 수 있게끔 바꿔줘야 합니다.
이를 위해 해주어야 하는 두 가지 것들이 있는데요!
UIViewControllerRepresentable
프로토콜을 만족하는 새로운 SwiftUI view를 만든다.- 이 view에
makeUIViewController()
와updateUIViewController()
메소드를 구현한다.
우선 SwiftUI View 에 넣기위해 UIViewController 를 만들어줄 필요가 있어요.
class NMapsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let mapView = NMFMapView(frame: view.frame)
view.addSubview(mapView)
}
}
제 경우에는 NaverMap을 그리기 위한 UIViewController를 만들어주었습니다.
그다음 이 UIViewController 를 View 로 바꾸어주기 위한 View를 만들어주어야해요!
UIViewControllerRepresentable
그 전에 UIViewControllerRepresentable 프로토콜을 살펴보면
protocol UIViewControllerRepresentable : View where Self.Body == Never
이렇게 생겼는데 보다시피 View protocol을 채택해고 있고 이 View의 body의 타입은 Never 입니다.
이 Never가 뭔지 구글링을 통해서 찾아봤는데 Swift 3.0부터 들어온 친구라는 설명과 함께 uninhabited type: Never 즉, 상속 받을 수 없는 타입이므로 get을 하거나 instance를 생성할 수 없는 타입이라고 하는데요... 이 부분은 잘 이해가 안가서 다른 예시나 자료를 찾아봐야 할 것 같아요 ;_;
struct MyView: UIViewControllerRepresentable {
typealias UIViewControllerType = NMapsViewController
func makeUIViewController(context: Context) -> NMapsViewController {
let vc = NMapsViewController()
return vc
}
func updateUIViewController(_ uiViewController: NMapsViewController, context: Context) {
}
}
이렇게 UIViewControllerRepresentable 프로토콜을 만족하는 MyView를 만들었는데 하나하나 살펴보면
typealias UIViewControllerType = NMapsViewController
이 부분은 이 view가 보여줄 UIViewControllerType을 명시적으로 정의해주는 부분이기 때문에 우리가 보여줄 뷰 컨트롤러를 넣어주면 됩니다.
makeUIViewController
이 부분에서 우리는
- view controller 객체를 생성하고
- 초기 값을 설정하기
우리의 view 의 경우에는 간단하기 때문에 NMapsViewController 객체를 생성하고 바로 반환해주었습니다.
updateUIViewController
이 메소드는 SwiftUI가 업데이트 되었을때 불리게 되는데요.
즉 우리의 view controller를 업데이트 하기 위한 부분이에요!.
이제 사용하자!
이렇게 메소드 생성까지 끝내면 사용법은 매우 간단한데, 우리가 만들어준 myView를 View 안에 넣어주면 됩니다!
struct ContentView: View {
@State var recommendedMenu: String = "음식 추천"
@State var isPresentedMap = false
private var menuDataManager: MenuDataManager = MenuDataManager()
var body: some View {
ZStack {
VStack {
Spacer()
Image(recommendedMenu)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 250)
.cornerRadius(30)
Text(recommendedMenu)
.font(.system(size: 30))
.padding(.bottom, 10)
Button {
isPresentedMap = true
} label: {
Text("GPS")
}.sheet(isPresented: $isPresentedMap) {
MyView()
}
Spacer()
Button {
recommendedMenu = menuDataManager.recommendMenu()
} label: {
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 170, height: 80)
Text("음식을 추천해드릴게요!").foregroundColor(.black)
}
}
Spacer()
.frame(height: 100)
}
.padding()
}
}
}
저는 버튼을 누르면 지도가 있는 sheet가 올라오도록 구현했습니다.
잘 작동되는 모습! 🥳🥳
/// 전체코드
import SwiftUI
import NMapsMap
class NMapsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let mapView = NMFMapView(frame: view.frame)
view.addSubview(mapView)
}
}
struct MyView: UIViewControllerRepresentable {
typealias UIViewControllerType = NMapsViewController
func makeUIViewController(context: Context) -> NMapsViewController {
let vc = NMapsViewController()
return vc
}
func updateUIViewController(_ uiViewController: NMapsViewController, context: Context) {
}
}
struct ContentView: View {
@State var recommendedMenu: String = "음식 추천"
@State var isPresentedMap = false
private var menuDataManager: MenuDataManager = MenuDataManager()
var body: some View {
ZStack {
VStack {
Spacer()
Image(recommendedMenu)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 250)
.cornerRadius(30)
Text(recommendedMenu)
.font(.system(size: 30))
.padding(.bottom, 10)
Button {
isPresentedMap = true
} label: {
Text("GPS")
}.sheet(isPresented: $isPresentedMap) {
MyView()
}
Spacer()
Button {
recommendedMenu = menuDataManager.recommendMenu()
} label: {
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 170, height: 80)
Text("음식을 추천해드릴게요!").foregroundColor(.black)
}
}
Spacer()
.frame(height: 100)
}
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
https://sarunw.com/posts/uiviewcontroller-in-swiftui/
위 링크를 참조했음을 밝힙니당 :)
'Swift' 카테고리의 다른 글
[Swift] Core Data 기본(Core Data Stack과 NSManagedObjectContext) (0) | 2024.11.17 |
---|---|
Electron 앱과 Swift Native 앱간 통신하기 (0) | 2024.09.04 |
[Swift] 서브스크립트(subscript)에 대해 알아보자! (0) | 2024.08.23 |
[Swift] Struct vs Class (0) | 2024.08.22 |
[Swift] Picker 숫자에 간격 주기 (0) | 2024.08.02 |