SwiftUI와 UIKit 통합하기

2 답변 글타래를 보이고 있습니다
  • 글쓴이
    • HyunJi
      참가자
      • 글작성 : 9
      • 답글작성 : 10

      요즘 SwiftUI에 대해서 공부를 많이 하고 있는데, SwiftUI을 UIKit에 통합하는 방법이 있어서 글을 쓰려고 한다.

      기본적으로 UIHostingController 사용으로 쉽게 통합할 수 있다.

      UIHostingController는 UIViewController의 하위 클래스이며, 이 클래스의 유일한 목적은 기존의 UIKit 기반의 프로젝트에 통합될 수 있도록 SwiftUI 뷰를 감싸는 것이다.

      UIHostingController를 사용하면 SwiftUI 뷰를 전체 화면으로 처리하거나 컨테이너 뷰에 호스팅 컨트롤러를 내장하여 기존 UIKit 화면 레이아웃 내에 개별 컴포넌트로 취급할 수 있다. 

      아래에 나올 프로젝트는 Storyboard 기반 Single View App으로 작성했다.

      SwiftUI 뷰를 전체 화면으로 처리하기

      프로젝트에 SwiftUI 콘텐트 뷰를 추가한다.

      import SwiftUI
      
      struct SwiftUIView: View {
      
      var text: String
      
      var body: some View {
      VStack {
      Text(text)
      HStack {
      Image(systemName: "smiley")
      Text("This is SwiftUI View")
      }
      }
      .font(.largeTitle)
      }
      }
      
      struct SwiftUIView_Previews: PreviewProvider {
      static var previews: some View {
      SwiftUIView(text: "Simple Text")
      }
      }
      
      

      위와 같이 SwiftUI 파일을 수정해준다.

      그리고 Main.storyboard 파일을 수정해준다.

      사용자가 현재 화면에서 뒤로 이동할 수 있도록 Navigation Controller 설정을 해준다.

      그리고 SwiftUI 통합으로 버튼이 필요하며, 해당 버튼을 클릭하면 SwiftUI View를 포함하는 새로운 ViewController가 표시되도록 하기 위해 버튼을 추가해준다.

      다음으로 스토리보드에 UIHostingController를 추가한다.


      버튼을 HostingView에 segue를 show로 설정해준다.

      그리고 segue 설정해준 것을 ViewController.swift파일에 액션을 구성해준다.

      import UIKit
      import SwiftUI
      
      class ViewController: UIViewController {
      
      override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view.
      }
      
      @IBSegueAction func howSwiftUIView(_ coder: NSCoder) -> UIViewController? {
      return UIHostingController(coder: coder, rootView: SwiftUIView(text: "Integrationr One"))
      }
      
      }
      
      

      SwiftUI를 임포트해주고, 세그 액션을 위와 같이 추가해준다.

      실행 화면은 다음과 같다.

      컨테이너 뷰 포함하기

      컨테이너 뷰가 기존의 뷰 컨테이너 화면에 추가되어 UIKit 컴포넌트들과 함께 SwiftUI 뷰가 포함하도록 한다.

      컨테이너 뷰를 뷰 컨트롤러에 추가하고, 기본으로 생기는 ViewController를 삭제하고, 스토리보드에 hosting controller를 다시 추가해준다.

      스토리보드에 추가된 hosting controller로 컨테이너뷰를 control+드래그로 Embed 설정해준다.

      이제 다음으로 IBSegueAction을 Container View와 호스팅 컨트롤러 사이의 연결에 추가할 것이다.

      @IBSegueAction func embedSwiftUIView(_ coder: NSCoder) -> UIViewController? {
      return UIHostingController(coder: coder, rootView: SwiftUIView(text: "Integration View"))
      }
      

      아까 만들었던 showSwiftUIView 함수 밑 부분에 embedSwiftUIView 함수를 만들어준다.

      실행 화면은 다음과 같이 SwiftUI 뷰가 처음에 나오는 뷰 컨트롤러의 Container View에 나타난다.

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 580

      좋은글 고맙습니다!
      지금의 SwiftUI는 마치 처음 탄생한 Swift 언어의 모습 같아요..
      아직은 30% 아쉬운… 30% 모자란 SwiftUI ㅠㅠ 얼른 좋아지길 바라봅니다…!

    • 멍단비
      참가자
      • 글작성 : 10
      • 답글작성 : 98

      몰랐는걸 알게됐네요. 잘봤습니다. 상황에따라서 위 방법으로 SwiftUI를 찔끔찔끔 넣어보는 것도 재밌겠네요. ㅎㅎ
      그렇게 연습을 좀 하다가 나중에 SwiftUI가 좀 안정되면 큰맘먹고 싹다 리팩토링 해버리는 것, 괜찮을 것 같습니다.

      (수정)
      아, 저도 워낙 초보라 몰랐는데 HostingViewController가 선택이아니라 필수네요.
      애초에 SwiftUI로 생성되는 프로젝트들의 SceneDelegate에 가보면 window의 rootViewController에 swiftUI view인 contentview를 rootview로 가지는 HostingViewController를 넣어주네요.
      아직 앱이 uiwindow기반이라서 그렇다고 하는 것 같아요. 틀린 점이나 부족한 설명은 댓글 부탁드립니다. 꾸벅~


      func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Create the SwiftUI view that provides the window contents. let contentView = ContentView() // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) self.window = window window.makeKeyAndVisible() } }
      • 이 답변은 멍단비에 의해 3 years, 11 months 전에 수정됐습니다.
      • 이 답변은 멍단비에 의해 3 years, 11 months 전에 수정됐습니다.
      • 이 답변은 멍단비에 의해 3 years, 11 months 전에 수정됐습니다.
      • 이 답변은 멍단비에 의해 3 years, 11 months 전에 수정됐습니다.
2 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom