programing

Swift 포함기존 UIKit 응용 프로그램의 UI 보기

yellowcard 2023. 4. 10. 21:31
반응형

Swift 포함기존 UIKit 응용 프로그램의 UI 보기

Swift로 뷰 작성 가능UI는 기존 UIKit 애플리케이션과 나란히 있습니까?

Objective-C로 작성된 기존 어플리케이션이 있습니다.스위프트 5로 이주를 시작했어스위프트를 사용할 수 있는지 궁금합니다.UI와 기존 UIKit .xib 보기를 함께 사용합니다.

즉, Swift로 뷰를 만들고 싶다.UI 및 기타 뷰는 같은 앱에서 UIKit으로 빌드됩니다.물론 둘 다 섞지 않는다.

SomeObjCSwiftProject/
    SwiftUIViewController.swift
    SwiftUIView.xib
    UIKitViewController.swift
    UIKitView.xib

서로 연계하여 작업하다

edit 06/19: 답변에서 @Departmento B가 제안한 UI Hosting Controller에 대한 정보를 추가했습니다.크레딧은 그에게 돌아간다!


Swift 사용UIKit 내의 UI

SwiftUI, 컴포넌트UIKit: ★★★★★★★★★★★★★★★★★★★★★★★★」SwiftUI ViewUIHostingController음음음같 뭇매하다

let swiftUIView = SomeSwiftUIView() // swiftUIView is View
let viewCtrl = UIHostingController(rootView: swiftUIView)

또, 이 기능을 무효로 할 수도 있습니다.UIHostingController 제작할 수 있습니다. 맞춤 할 수 .예예 、 를를 、 ,를 、preferredStatusBarStyle하지 않는 으로, 「」를 사용해 .SwiftUI역시나

UIHostingController는 여기에 기재되어 있습니다.


Swift 내에서 UIKit 사용UI

의 「」의 .UIKit는 「」로 가 있습니다.SwiftUI ,,,UIViewRepresentable프로토콜이 도움이 됩니다!여기에 기재되어 있으며, Apple의 공식 튜토리얼에서 실제로 동작하고 있는 것을 확인할 수 있습니다.


호환성.

, 사용하실 수 .SwiftUI버전에서는, 、、< 、、 。SwiftUI는 iOS 13 이상에서만 사용할 수 있습니다.상세한 것에 대하여는, 이 투고를 참조해 주세요.

「 」를 사용하고 SwiftUI 이하의 에서는, 「iOS 13」에를 붙일 필요가 .SwiftUI「」가 붙은 @available(iOS 13.0.0, *)기여하다.

Swift를 포함하려면UI를 UEKit 보기 컨트롤러로 변환하고 컨테이너 보기를 사용합니다.

class ViewController: UIViewController {
    @IBOutlet weak var theContainer: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let childView = UIHostingController(rootView: SwiftUIView())
        addChild(childView)
        childView.view.frame = theContainer.bounds
        theContainer.addSubview(childView.view)
        childView.didMove(toParent: self)
    }
}

언급

UI Hosting 컨트롤러

수업 시간에 대한 문서가 작성되지 않았지만 재 업 성 았 료 지 되 although at has,ation않 the만 the, class작지 the written been자수 not moment for는 document현 has although atUIHostingController<Content>찾고 계신 것 같습니다.https://developer.apple.com/documentation/swiftui/uihostingcontroller

방금 앱에서 다음 코드 행으로 시도했습니다.

let vc = UIHostingController(rootView: BenefitsSwiftUIView())

디 어디 있죠?BenefitsSwiftUIView is just the default "Hello World" 기본 "Hello World" 입니다.View부에서SwiftUI. 이것은 당신이 기대만큼 잘해요.이것은 당신이 예상한 대로 작동합니다.로도 합니다.UIHostingController.

제가 아직 본 적이 없는 아이템 중 하나는 Xcode 11 beta 5 (11M382q)와 관련된 것으로, 앱의 info.plist 파일을 갱신하는 것입니다.

시나리오에서는 기존 Swift 및 UIKit 기반 애플리케이션을 iOS 13 및 순수 Swift로 완전히 이행합니다.UI 앱이기 때문에 이전 버전과의 호환성은 신경 쓰지 않습니다.

AppDelegate에서 필요한 변경을 한 후:

// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication,
                 configurationForConnecting connectingSceneSession: UISceneSession,
                 options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    return UISceneConfiguration(name: "Default Configuration",
                                sessionRole: connectingSceneSession.role)
}

SceneDelegate 클래스에 추가:

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: HomeList())
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

SceneDelegate가 호출되지 않는 문제가 발생했습니다.이 문제는 다음 사항을 info.plist 파일에 추가함으로써 해결되었습니다.

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <false/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string></string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                <key>UISceneConfigurationName</key>
                <string>Default Configuration</string>
                <key>UISceneStoryboardFile</key>
                <string>LaunchScreen</string>
            </dict>
        </array>
    </dict>
</dict>

스크린샷은 다음과 같습니다.

동기화 상태를 유지하는 주요 항목은 다음과 같습니다.

  • 클래스 이름을 위임하여 Xcode가 검색 위치를 알 수 있도록 합니다.SceneDelegate파일
  • AppDelegate 콜이 올바른 콜을 로드할 수 있도록 설정 이름UISceneConfiguration

이렇게 하면 새로 만든 HomeList 뷰(A Swift)를 로드할 수 있었습니다.UI 오브젝트)

레이아웃에 문제가 있는 경우 UI Hosting Controller 뷰에 제약을 추가해야 합니다.

class ViewController: UIViewController {
    @IBOutlet weak var theContainer: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let childView = UIHostingController(rootView: SwiftUIView())
        addChild(childView)
        childView.view.frame = theContainer.bounds
        theContainer.addConstrained(subview: childView.view)
        childView.didMove(toParent: self)
    }
}

다음 확장자를 사용합니다.

extension UIView {
    func addConstrained(subview: UIView) {
        addSubview(subview)
        subview.translatesAutoresizingMaskIntoConstraints = false
        subview.topAnchor.constraint(equalTo: topAnchor).isActive = true
        subview.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        subview.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        subview.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }
}

방법은 다음과 같습니다.

Swift 만들기UI 어댑터

/**
 * Adapts a SwiftUI view for use inside a UIViewController.
 */
class SwiftUIAdapter<Content> where Content : View {

    private(set) var view: Content!
    weak private(set) var parent: UIViewController!
    private(set) var uiView : WrappedView
    private var hostingController: UIHostingController<Content>

    init(view: Content, parent: UIViewController) {
        self.view = view
        self.parent = parent
        hostingController = UIHostingController(rootView: view)
        parent.addChild(hostingController)
        hostingController.didMove(toParent: parent)
        uiView = WrappedView(view: hostingController.view)
    }

    deinit {
        hostingController.removeFromParent()
        hostingController.didMove(toParent: nil)
    }

}

다음과 같이 뷰 컨트롤러에 추가합니다.

class FeedViewController: UIViewController {
    
    var adapter : SwiftUIAdapter<FeedView>!

    override required init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        adapter = SwiftUIAdapter(view: FeedView(), parent: self)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    /** Override load view to load the SwiftUI adapted view */
    override func loadView() {
        view = adapter.uiView;
    }
}

래핑된 뷰의 코드

래핑 뷰는 자동 레이아웃이 아닌 수동 레이아웃(layoutSubViews)을 사용합니다.이 경우는 매우 간단합니다.

class WrappedView: UIView {

    private (set) var view: UIView!

    init(view: UIView) {
        self.view = view
        super.init(frame: CGRect.zero)
        addSubview(view)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        view.frame = bounds
    }
}

를 작성하려면SwiftUI기존 Objective C 프로젝트의 뷰는 이 기술이 나에게 완벽하게 적용되었습니다.

'Swift 추가'UI에서 Objective-C 애플리케이션으로

그 글을 쓴 친구에게 찬사를 보냅니다.

스토리보드 포함

사용할 수 있습니다.HotingViewController컴포넌트:

프리뷰

그럼 심플한 게 있으면HotingController다음과 같습니다.

class MySwiftUIHostingController: UIHostingController<Text> {
    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: Text("Hello World"))
    }
}

컨트롤러의 커스텀클래스로 설정할 수 있습니다.

프리뷰 2


코드 포함

let mySwiftUIHostingController = UIHostingController(rootView: Text("Hello World"))

그리고 보통처럼 사용할 수 있습니다.UIViewController


중요사항

Import하는 것을 잊지 마세요.SwiftUI필요한 곳이면 언제든지UIHostingController

이러한 순서는, 간단하게 실행할 수 있습니다.

  1. mainStoryBoard에 표시되는 viewController에 버튼을 만들고 Swift를 가져옵니다.UI

  2. mainStoryboard에 hostingViewController를 추가하고 버튼에서 hostingViewController로 Segue(Segue 표시)를 드래그합니다.storyBoard에서 Swift로 segue 끌기UI

  3. Swift 추가Cmd+N Creating Swift를 클릭하여 프로젝트의 UI 파일UI 파일

  4. mainStoryBoard에 표시되는 segueAction 폼 segue를 viewController에 추가합니다.

  5. segueAction에 코드 폴링 라인 쓰기...

@IBSegueAction func ActionMe(_ coder: NSCoder) -> UIViewController? {
    return UIHostingController(coder: coder, rootView: SWIFTUI())
}

같이 쓰셔도 돼요.전송 할 수 있습니다.UIView로.View타고UIViewRepresentable준거성자세한 내용은 공식 튜토리얼에서 확인할 수 있습니다.

그러나 호환성도 고려해야 합니다.

여기 프로토콜의 코드 조각이 있습니다.ViewSwift의UI:

///
/// You create custom views by declaring types that conform to the `View`
/// protocol. Implement the required `body` property to provide the content
/// and behavior for your custom view.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View : _View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    /// ...
}

따라서 역호환성이 없습니다.

  • iOS 13.0 이상
  • MacOS 10.15 이상
  • 감시 OS 6.0+
import Foundation
    #if canImport(SwiftUI)
    import SwiftUI

internal final class SomeRouter {
    fileprivate weak var presentingViewController: UIViewController!

    function navigateToSwiftUIView() {
       if #available(iOS 13, *) {
            let hostingController = UIHostingController(rootView: contentView())  
presentingViewController?.navigationController?.pushViewController(hostingController, animated: true)
            return
        }
        //Keep the old way when not 13.
}
#endif

언급URL : https://stackoverflow.com/questions/56433826/include-swiftui-views-in-existing-uikit-application

반응형