SwiftUI 는 너무 씽나서 앱 전체에 사용하는 걸 참을쑤가 없써!!
하지만 많은 앱들은 이미 UIKit으로 개발되어 있어서 코드 전체를 SwiftUI로 다시 짤 수 는 없는데 어떻게 하면 좋을까?
당연히 Apple이 그 생각도 했지.
이미 개발된 UIKit 앱에 SwiftUI view를 추가하는 것을 "super-easy" 하게 만들어 놨다.
조금 코드를 더 작성하면 SwiftUI view 와 데이터를 교환하는 UIKit view 도 만들수 있다.
이런 부분을 통해 SwiftUI Control의 단점을 극복할 수 도 있을 것 이다.
*hosting 이라는 용어는 UIKit 앱이 SwiftUI view 를 host 할 수 있어서 붙여진 용어이다. (반대로도 가능)
이번장에서 배울 것은
- Host SwiftUI view in UIKit (UIKit 안에 SwiftUI 넣기)
- Host view controller in SwiftUI Project (SwiftUI 에 viewcontroller 넣기)
- Host UIKit view with data dependencies in SwiftUI Project (데이터 의존성이 있는 UIKit View를 SwiftUI 프로젝트에 넣기)
*SwiftUI 를 사용하기 위해서는 deployment target 을 iOS13 이상으로 해야한다.
UIKit 프로젝트에 SwiftUI view 호스팅하기
- SwiftUI view 파일을 프로젝트에 추가한다.
- SwiftUI view present 를 위한 버튼을 추가한다.
- Hosting Controller 를 Storyboard 로 drag 하여 segue 를 만든다.
- segue를 view controller code에 있는 @IBSegueAction에 연결하고 hosting controller 의 rootView를 너의 SwiftUI view의 instance로 설정한다.
@IBSegueAction 은 Xcode11 에서 새로나온 기능이다.
UIKit앱을 prepare(for:sender:) 대신에 사용할 수 있다.
특히 destination view controller를 생성할때 프로퍼티를 세팅하고 싶을때 유용하다.
segue 에 직접적으로 연결되기 때문에 segue 식별자도 필요하지 않다.
SwiftUI 프로젝트에 view controller hosting 하기
- ViewController.swift 와 Storyboard 를 SwiftUI 프로젝트에 추가한다.
- storyboard의 identity inspector 에 Storyboard ID를 설정한다.
- ViewController 의 표현을 위한 구조체를 만든다.
- ContentView에 NavigationLink를 달아준다.
* 표현을 위한 구조체는 해당 view controller 의 class 외부에 있어야한다. 구조체 이름은 view controller 와 일치하지 않아도 되지만 withIdentifier 파라미터는 Storyboard ID 와 동일해야 한다.
UIViewControllerRepresentable 프로토콜은
make와 update 메소드를 필요로 한다. makeUIViewController(context:)의 경우 ViewController 를 지정된 Storyboard에서 인스턴스화 시키켜준다. (그래서 storyboard ID 가 필요하다)
updateUIViewController(_:context:)는 비운체로 놔둘 것이다. 왜냐하면 현재 ViewController 는 SwiftUI view 의 데이터를 사용하지 않기 때문이다.
SwiftUI view 가 ViewController 쪽의 데이터를 사용하지 않기 때문에 ViewControllerRepresentation은 필요가 없지만 구현해놓는게 좋다.
Navigating to the view Controller
1. 화면이동을 위한 버튼을 만들어 준다.
NavigationLink(destination: ViewControllerRepresentation()) {
Text("Play BullsEye")
}
2. 이동에 필요한 정보를 세팅해준다.
- 최상단 계층의 VStack을 NavigationView로 감싸주면서 NavigationLink 가 동작하게 만든다.
- 최상단 VStack의 navigation bar title을 설정한다.
- NavigationView에게 default split-view navigation view style를 적용해준다.
*이동된 viewcontroller 의 title 은 viewWillApprear 에서 정해줄 수 있다.
Previewing UIKit views
UIViewControllerRepresentable을 준수하면 view controller 도 preview 를 볼 수 있다! 와우
Hosting UIKit view with data dependencies
SwiftUI 의 Slider를 UISlider로 바꿔보자
어떤 상황이냐면 UIKit의 slider는 thumbTintColor 프로퍼티가 있지만 SwiftUI Slider는 해당 프로퍼티가 없다. 그래서 UISlider를 통해 그 프로퍼티에 접근하려 한다.
프로세스는 view controller 를 hosting 하는 것과 비슷하다.
- UIViewRepresentable를 준수하는 SwiftUI view 를 만든다.
- UIKit view를 인스턴스화 하기 위한 make 메서드를 구현한다.
- UIKit view를 SwiftUI view 로부터 업데이트 할 수 있는 update 메서드를 구현한다.
- Coordinator 를 만들고 target-action 메서드를 구현하여 SwiftUI view 로부터 UIKit view 를 업데이트 한다.
*간단한 UIView를 빠르게 wrapping 하려면 generic type 을 쓰는게 좋다. 아래 참고
Updating UIView from SwiftUI
한가지 다뤄야 하는 문제점은 UIKit과 SwiftUI의 color type 이 다르다는 점이다.
SwiftUI의 Color 는 View이고 UIColor는 View 가 아니다. 다행히 UIColor 값으로 부터 Color view를 만들 수 있다. Color(UIColor.red)
다른 문제점은 UISlider(Float) 와 Slider(Double) 의 값 타입이 다르다.
가장 쉬운 방법은 Double 로 부터 Float를 만드는 것 이다.
ColorUISlider의 @Binding 은 ContentView의 @State를 참조하는 것 이다.
UIView 와 SwiftUI view 의 데이터 동등하게 다루기
updateUIView(_:context:) 에 uiview.value = Float(self.value)로 업데이트 된 값을 할당 해주는 코드 작성
이렇게 UIKit control 이 SwiftUI 의 값을 받을 수 있다.
SwiftUI view 의 ColorUISlider가 UIKit control 의 UISlider의 데이터와 동기화 되도록 하는 Coordinator 가 필요하다.
위와 같이 ColorUISlider 구조체 안에 Coordinator class 를 만들면 makeCoordinator() 메서드를 구현해 주어야 한다.
이로써 coordinator 에세 parent ColorSlider(underlying UIView 는 UISlider) 를 연결해 주었다.
coordinator의 목적은 UISlider의 값을 ColorSlider프로퍼티 값에 전달하는 것 이다. ContentView에 있는 @State 변수를 참조하는 것 인데 바인딩 됨으로써 UISlider 값이 ContentView를 효과적으로 업데이트 시킬 수 있는 것 이다.
UISlider 값을 받기 위해 coordinator 는 UISlider control 이벤트인 valueChanged를 구현해야 한다. 해당 이벤트를 target-action 으로 parent view의 makeUIView(context:) 내에 명시해 준다.
전형적인 UIKit 의 addTarget(_:axtion:for:) 메서드를 통해 UISlider control 의 valueChagned 이벤트의 Target을 Coordinator의 updateColorUISlider(_:) action 으로 잡았다.
*underlying UIView가 꼭 control이 있어야 되는건 아니다. MKMapViewDelegate 와 같은 delegate protocol 도 적용 가능하다.
이로써 UISlider 와 ColorUISlider와의 쌍방향 소통이 가능해 졌다.
ColorUISlider 를 ContentView 에 적용
'iOS > SwiftUI' 카테고리의 다른 글
#7 Controls & User Input (0) | 2020.10.21 |
---|---|
#6 Intro to Controls: Text & Image (0) | 2020.10.21 |
#5 The Apple EcoSystem (0) | 2020.10.20 |
#3 Understanding SwiftUI (0) | 2020.10.19 |
#2 SwiftUI Getting Started (0) | 2020.10.19 |
댓글