이번에 스유 공부를 하면서 UIKit을 사용해야하는 경우를 많이 만나보았는데 UIHostingController 과 UIViewRepresentable 을 통해서 사용을 했었는데 말이죠
근데 굳이 뷰컨을 새로 만들어서 기능을 끌고오는거보다 부분적으로 바로 사용하면 좋겟다는 생각이 들엇어요!
그래서 한번 끄적여봣는데 잘못된 부분이나 질문 환영입니다
viewExtractor하기
//
// ContentView.swift
// extract
//
// Created by 이지훈 on 12/3/24.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
// 시스템 이미지 설정
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
// NavigationStack 예제
NavigationStack {
List {
}
.navigationTitle("Home")
.viewExtractor { view in
if let navController = view.next as? UINavigationController {
print(navController)
}
}
}
// TextField 예제
TextField("Hello World", text: .constant(""))
.viewExtractor { view in
if let textField = view as? UITextField {
print(textField)
}
}
// Slider 예제
Slider(value: .constant(0.2))
.viewExtractor { view in
if let slider = view as? UISlider {
slider.tintColor = .red
slider.thumbTintColor = .systemBlue
}
}
}
.padding()
}
}
// UIKit 뷰 추출을 위한 extension
extension View {
@ViewBuilder
func viewExtractor(result: @escaping (UIView) -> ()) -> some View {
self
.background(ViewExtractHelper(result: result))
.compositingGroup()
}
}
// UIKit 뷰 추출을 돕는 헬퍼 구조체
fileprivate struct ViewExtractHelper: UIViewRepresentable {
var result: (UIView) -> ()
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: .zero)
view.backgroundColor = .clear
view.isUserInteractionEnabled = false
DispatchQueue.main.async {
if let uiKitview = view.superview?.superview?.subviews.last?.subviews.first {
result(uiKitview)
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
코드설명
Composite group을 통해서 모든 것을 하나로 묶어주는 컨테이너라고 생각하고이 그룹을 통해서 SwiftUI는가 "Wrapped UIView"라는 것을 만들게 됩니다!
- 배경 뷰 (extractor view라고 함)
- 작업 중인 SwiftUI 뷰
이미지에 보이는 계층 구조를 자세히 뜯어보면
- 최상단에는 "Grouped View" (superView.superView로 접근)
- 그 안에 배경으로 사용되는 "Extractor View"
- 그 다음 SwiftUI View가 있습니다 (subviews.last로 접근)
- SwiftUI View 안에는 "Hosting Kind a View"가 있습니다
- 마지막으로 맨 아래에 UIKit View가 있습니다 (subviews.first로 접근)
만약 뷰가 순수하게 SwiftUI로만 만들어졌고 UIKit 컴포넌트를 전혀 사용하지 않는다면, 이 계층 구조의 맨 아래에 UIKit 뷰가 존재하지 않으니, 이런 경우에는 UIKit 뷰를 찾으려고 하면nil로 반환됩니다.
UIHostingController의 차이점
먼저, UIHostingController의 특징을 살펴보면:
let swiftUIView = MySwiftUIView()
let hostingController = UIHostingController(rootView: swiftUIView)
UIHostingController는 SwiftUI 뷰를 UIKit 환경에서 사용할 때 주로 사용합니다. 즉, UIKit → SwiftUI 방향으로의 통합을 위한 도구입니다.
하지만 이런식으로 ViewExtractHelper를 사용해서 접근한다면
- SwiftUI → UIKit 방향으로의 접근이 가능합니다 (SwiftUI 환경을 유지하면서 UIKit의 세밀한 컨트롤이 필요할 때 사용가능)
- 전체 ViewController를 생성하지 않고도 UIKit 뷰에 접근할 수 있다
(TextField, Slider 같은 기본 컴포넌트들의 UIKit 속성에 접근할 때 매우 유용합니다. 전체 ViewController를 만들지 않고도 필요한 부분만 Custom이 가능해집니다!)
'IOS - Swift > SwiftUI' 카테고리의 다른 글
[iOS] UIkit + SwiftUI 둘다 사용하기! (1) | 2024.11.27 |
---|---|
[iOS/SwiftUI] Property Wrapper - 기본편 (1) | 2024.03.29 |
[iOS/SwiftUI] LunchScreen 적용하기 (0) | 2023.12.31 |