SwiftUIで新しいビューを表示する


11

ボタンをクリックしてpresent modally、UIKitのように新しいビューを表示したい ここに画像の説明を入力してください

シートを使用して新しいビューを表示する方法」は既に見ましたが、モーダルシートとしてメインビューにアタッチしたくありません。

またNavigationLink、新しいビューと古いビューにナビゲーション関係を持たせたくないので、は使いたくありません。

ご協力いただきありがとうございます...


モーダルシートとしてメインビューに添付したくないのはなぜですか。でも標準的な方法UIKitです。何か特別な理由はありますか?
Mojtaba Hosseini、

私の考えを説明しようと思います…何か問題があれば訂正してください。
CHウィング

アプリには3つのビューがあります。1:ログインページ2:TableViewページ3:TableDetailページ、TableViewページ、TableDetailページはナビゲーションリレーションです。ログインがTableViewページに表示された後、TableViewページはログイン後のログインページと何の関係もありません
CH Wing

それであなたはそれがfullscreen正しい必要がありますか?
Mojtaba Hosseini、

ys!欲しいfullscreen
CHウィング

回答:


12

モーダルを表示するには(iOS 13スタイル)

sheet自分自身を閉じる機能を備えたシンプルなものが必要です:

struct ModalView: View {
    @Binding var presentedAsModal: Bool
    var body: some View {
        Button("dismiss") { self.presentedAsModal = false }
    }
}

そしてそれを次のように提示してください:

struct ContentView: View {
    @State var presentingModal = false

    var body: some View {
        Button("Present") { self.presentingModal = true }
        .sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
    }
}

注意私は渡されたpresentingModalあなたがモーダル自体からそれを退けることができますが、あなたはそれを取り除くことができるようにモーダルに。


本当に存在させるにはfullscreen(視覚的にだけではありません)

にアクセスする必要がありますViewController。だからあなたはいくつかのヘルパーコンテナと環境のものが必要です:

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

次に、この拡張機能を実装する必要があります。

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        self.present(toPresent, animated: true, completion: nil)
    }
}

最終的に

あなたはそれを次のfullscreenようにすることができます:

struct ContentView: View {
    @Environment(\.viewController) private var viewControllerHolder: UIViewController?

    var body: some View {
        Button("Login") {
            self.viewControllerHolder?.present(style: .fullScreen) {
                Text("Main") // Or any other view you like
            }
        }
    }
}

すごい!詳細なソリューションに感謝
CH Wing

環境プロパティラッパーでこのエラーが発生します:タイプ 'Environment <UIViewController?>'の値を指定されたタイプ 'UIViewController'に変換できません
jsbeginnerNodeJS

デフォルトで処理されるはずですが?、行末に追加してみてください。@jsbeginnerNodeJS
Hosseini

私は、コンソールでこのエラーを取得する: `` `警告:現在までの試み<_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_:0x7fafd2641d30> <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_:0x7fafd2611bd0>でそのビューウィンドウ階層に存在しない` ``!
jsbeginnerNodeJS

どのようにそれを却下しますか?
gabrielapittari

0

これが単純な一方向です-前方ビュー。それは非常に簡単です。

        struct ChildView: View{
           private  let colors: [Color] = [.red, .yellow,.green,.white]
           @Binding var index : Int
           var body: some View {
           let next = (self.index+1)  % MyContainer.totalChildren
             return   ZStack{
                    colors[self.index  % colors.count]
                     Button("myNextView \(next)   ", action: {
                    withAnimation{
                        self.index = next
                    }
                    }
                )}.transition(.asymmetric(insertion: .move(edge: .trailing)  , removal:  .move(edge: .leading)  ))
            }
        }

        struct MyContainer: View {
            static var totalChildren = 10
            @State private var value: Int = 0
            var body: some View {
                    HStack{
                        ForEach(0..<(Self.totalChildren) ) { index in
                            Group{
                            if    index == self.value {
                                ChildView(index:  self.$value)
                                }}
                            }
                }
                }
        }

-1

免責事項:以下は実際には「ネイティブモーダル」のようではなく、動作もルックアンドフィールもありませんが、あるビューから別のビューへのカスタムトランジションが必要になり、トップビューのみをアクティブにする場合は、次のアプローチが役立つ場合があります。

したがって、次のようなものが予想される場合

カスタムSwiftUIモーダル

これはデモアプローチの簡単なコードです(corseアニメーションと遷移パラメータは希望に応じて変更できます)

struct ModalView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = false
                }
            }) {
                Text("Hide modal")
            }
            Text("Modal View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.green)
    }
}

struct MainView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = true
                }
            }) {
                Text("Show modal")
            }
            Text("Main View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.yellow)
    }
}

struct ModalContainer: View {
    @State var showingModal = false
    var body: some View {
        ZStack {
            MainView(activeModal: $showingModal)
                .allowsHitTesting(!showingModal)
            if showingModal {
                ModalView(activeModal: $showingModal)
                    .transition(.move(edge: .bottom))
                    .zIndex(1)
            }
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.