SwiftUI에서 전체 화면 모달 표시 (iOS13)

SwiftUI(iOS13)에서 전체 화면 모달 표시



오랜만의 기사가 됩니다. 좋은 아침 안녕하세요 화상입니다!
오늘은 재작년 Apple로부터 발표되어 화제가 되고 있는 SwiftUI에 대한 기사를 써 가고 싶습니다

SwiftUI 2는 iOS13에서는 사용할 수 없습니다.



현재(2021.3월 시점)에서는 SwiftUI는 ver.2까지 릴리스되고 있습니다만, 불행하게도 SwiftUI 2에서 릴리스된 기능은 iOS13에서 사용할 수 없습니다. SwiftUI 1에서는 일반적인 앱에 필요한 기능이 전혀 갖추어지지 않고, 2이상으로 라이브러리나 UIKit에 의존하게 됩니다.

필수급 라이브러리
SwiftUIX
↑ SwiftUI에 아직 구현되지 않은 것을 보완 해줍니다. 설명서가없는 것이 칠라 호라있는 것이 유감입니다 ...

그런데, 본제인 풀 스크린의 모달입니다만, 공식으로부터는 「.fullScreenCover」라고 하는 것이 준비되어 있습니다만 이쪽은 SwiftUI 2로부터 등장한 것이 되고 있어 유감스럽지만 iOS13에서는 사용할 수 없습니다.
그래서 이번 iOS13에서도 사용할 수있는 풀 스크린 모달을 만들어 갑시다!

※ 덧붙여서 필자, 처음 iOS 앱 구현이 SwiftUI가되어있어 UIKit도 현재 절찬 공부 중이므로 손 부드럽게 (웃음)

전체 화면 모달 구현



1. UIApplication 확장



UIApplication을 확장하여 최상위 컨트롤러를 얻는 메서드와 전체 화면 모달을 닫는 메서드를 만듭니다.

UIApplication+Extension.swift
extension UIApplication {
    /// 一番上にあるコントローラーを取得する
    public func getTopViewController() -> UIViewController? {
        guard let window = UIApplication.shared
                .connectedScenes
                .filter({$0.activationState == .foregroundActive})
                .map({$0 as? UIWindowScene})
                .compactMap({$0})
                .first?.windows.first else {
            return nil
        }

        window.makeKeyAndVisible()

        guard let rootViewController = window.rootViewController else {
            return nil
        }

        var topController = rootViewController
        while let newTopController = topController.presentedViewController {
            topController = newTopController
        }

        return topController
  }

    /// フルスクリーンのモーダルを閉じる
    public func closeModalView() {
        UIApplication.shared.getTopViewController()?.dismiss(animated: true, completion: nil)
    }
}

2. View 확장



다음은 SwiftUI의 View에서 SheetView나 FullCreenCover와 같이 풀 스크린 모달을 사용할 수 있도록 View를 확장해 나갑니다.

View+Extension.swift
extension View {
    public func fullScreenView<Content>(
        isPresented: Binding<Bool>,
        @ViewBuilder content: @escaping () -> Content
    ) -> some View where Content: View {
        if isPresented.wrappedValue {
            let window = UIApplication.shared.windows.last
            window?.isHidden = true

            let view = content()
            let viewController = UIHostingController(rootView: view)
            viewController.modalPresentationStyle = .fullScreen

            DispatchQueue.main.async {
                guard let tvc = UIApplication.shared.getTopViewController() else {
                    return
                }

                tvc.present(viewController, animated: true, completion: nil)
                isPresented.wrappedValue = false
            }
        }

        return self
    }
}

실제로 사용해 보자!



실제로 View에서 사용합시다! 이번 적당한 샘플 View를 준비해 보았습니다!
이쪽 참고에 여러분 부디 사용해 보세요

ContentView.swift
struct ContentView: View {
    @State private var showModal: Bool = false

    var body: some View {
        VStack {
            Spacer()
            Button(action: {
                showModal.toggle()
            }, label: {
                Text("フルスクリーンのモーダルを表示する")
            })
            Spacer()
        }
        .fullScreenView(isPresented: $showModal) {
            ModalView()
        }
    }
}

struct ModalView: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            Button(action: {
                UIApplication.shared.closeModalView()
            }, label: {
                Text("閉じる")
            })
        }
    }
}



마지막으로



iOS13에서 SwiftUI와 Combine을 사용할 때 특히 iOS13.0에서 iOS13.2까지는 조심하십시오. 버그가 꽤 많이...
게다가, 우리가 나쁜 것에 시뮬레이션에서는 재현하지 않고 실기만으로 재현하는 버그도 몇가지 있습니다.

실제 기기가 없으면 SwiftUI를 iOS13에서 사용하지 않는 것이 좋습니다
그래도 iOS13을 포함하고 싶다면 최소한 iOS13.3 이상으로 만드십시오.

Let's Enjoy SwiftUI! !

좋은 웹페이지 즐겨찾기