web-dev-qa-db-ja.com

SwiftUI-SwiftUIに相当するpopViewControllerはありますか?

私はSwiftUIで遊んでいて、ボタンをタップしたときに前のビューに戻ることができるようにしたいので、popViewControllerUINavigationController内で使用します。これまでに提供された方法はありますか?

私はNavigationDestinationLinkを使用して成功させることも試みました。

struct AView: View {
    var body: some View {
        NavigationView {
            NavigationButton(destination: BView()) {
                Text("Go to B")
            }
        }
    }
}

struct BView: View {
    var body: some View {
        Button(action: {
            // Trying to go back to the previous view
            // previously: navigationController.popViewController(animated: true)
        }) {
            Text("Come back to A")
        }
    }
}
41

BView構造体を次のように変更します。ボタンは、popViewControllerがUIKitで行ったのと同じように実行されます。

struct BView: View {
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
    var body: some View {
        Button(action: { self.mode.wrappedValue.dismiss() })
        { Text("Come back to A") }
    }
}
24
Chuck H

必要に応じて、プログラムでNavigationViewをポップする方法があります。これはベータ5です。

戻るボタンは必要ないことに注意してください。プログラムによって、DetailViewのshowSelfプロパティを任意の方法でトリガーできます。また、マスターに「プッシュ」テキストを表示する必要はありません。それはEmptyView()である可能性があり、それによって目に見えないセグエを作成します。

(新しいNavigationLink機能は、非推奨のNavigationDestinationLinkを引き継ぎます)

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            MasterView()
        }
    }
}

struct MasterView: View {
    @State var showDetail = false

    var body: some View {
        VStack {
            NavigationLink(destination: DetailView(showSelf: $showDetail), isActive: $showDetail) {
                Text("Push")
            }
        }
    }
}

struct DetailView: View {
    @Binding var showSelf: Bool

    var body: some View {
        Button(action: {
            self.showSelf = false
        }) {
            Text("Pop")
        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif
6
MScottWaller

これは私にとってwatchOSで動作するようです(iOSでは試していません):

@Environment(\.presentationMode) var presentationMode

そして、あなたがポップする必要があるとき

self.presentationMode.wrappedValue.dismiss()
4
Cherpak Evgeny

大量の基本的なナビゲーション機能は非常にバグが多いようです。これはがっかりすることであり、イライラの時間を節約するために、今は立ち去る価値があるかもしれません。私にとって、機能するのはPresentationButtonだけです。 TabbedViewタブが適切に機能せず、NavigationButtonがまったく機能しません。 NavigationButtonが機能する場合、YMMVのように聞こえます。

彼らがオートコンプリートを修正すると同時に修正されることを願っています。これにより、何が利用可能であるかについてより良い洞察が得られます。それまでの間、しぶしぶコーディングし、修正が出たときのメモをとっています。私たちが何か悪いことをしているのか、それともうまくいかないのかを理解するのは面倒ですが、それはあなたにとってベータ版です!

4
Sean C. Li

更新:このソリューションのNavigationDestinationLink APIは、iOS 13 Beta 5で非推奨になりました。isActiveバインディングでNavigationLinkを使用することをお勧めします。

NavigationDestinationLinkを使用して、NavigationViewのビューのプログラムによるプッシュ/ポップのソリューションを見つけました。

以下に簡単な例を示します。

import Combine
import SwiftUI

struct DetailView: View {
    var onDismiss: () -> Void

    var body: some View {
        Button(
            "Here are details. Tap to go back.",
            action: self.onDismiss
        )
    }
}

struct MainView: View {
    var link: NavigationDestinationLink<DetailView>
    var publisher: AnyPublisher<Void, Never>

    init() {
        let publisher = PassthroughSubject<Void, Never>()
        self.link = NavigationDestinationLink(
            DetailView(onDismiss: { publisher.send() }),
            isDetail: false
        )
        self.publisher = publisher.eraseToAnyPublisher()
    }

    var body: some View {
        VStack {
            Button("I am root. Tap for more details.", action: {
                self.link.presented?.value = true
            })
        }
            .onReceive(publisher, perform: { _ in
                self.link.presented?.value = false
            })
    }
}

struct RootView: View {
    var body: some View {
        NavigationView {
            MainView()
        }
    }
}

これについてはブログの投稿 here で書きました。

3
Ryan Ashcraft

状態変数あり。やってみて。

struct ContentViewRoot: View {
    @State var pushed: Bool = false
    var body: some View {
        NavigationView{
            VStack{
                NavigationLink(destination:ContentViewFirst(pushed: self.$pushed), isActive: self.$pushed) { EmptyView() }
                    .navigationBarTitle("Root")
                Button("Push"){
                    self.pushed = true
                }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}


struct ContentViewFirst: View {
    @Binding var pushed: Bool
    @State var secondPushed: Bool = false
    var body: some View {
        VStack{
            NavigationLink(destination: ContentViewSecond(pushed: self.$pushed, secondPushed: self.$secondPushed), isActive: self.$secondPushed) { EmptyView() }
                .navigationBarTitle("1st")
            Button("Push"){
                self.secondPushed = true;
            }
        }
    }
}



struct ContentViewSecond: View {
    @Binding var pushed: Bool
    @Binding var secondPushed: Bool

    var body: some View {
        VStack{
            Spacer()
            Button("PopToRoot"){
                self.pushed = false
            } .navigationBarTitle("2st")

            Spacer()
            Button("Pop"){
                         self.secondPushed = false
                     } .navigationBarTitle("1st")
            Spacer()
        }
    }
}

enter image description here

2

以下はXCode11 GMで私のために働きます

self.myPresentationMode.wrappedValue.dismiss()
1
guru

編集:ここでのこの答えは私のものより優れていますが、どちらも機能します:SwiftUI dismiss modal

あなたが本当に欲しがっている(または欲しがるべき)のはモーダルプレゼンテーションであり、ここで数人が言及しました。あなたがその道を進むなら、あなたは間違いなくプログラム的にモーダルを閉じることができる必要があるでしょう、そしてエリカ・サドゥンはここでそれを行う方法の素晴らしい例を持っています: https://ericasadun.com/2019/06/16/swiftui-modal-presentation /

宣言型コーディングと命令型コーディングの違いを考えると、自明ではない解決策(ブール値をfalseに切り替えてモーダルを閉じるなど)があるかもしれませんが、モデルの状態が真ではなく、 UI自体の状態。

エリカの例を簡単に紹介します。TestModalに渡されたバインディングを使用して、ContentView自体のメンバーでなくてもそれを閉じることができるようにします(簡単にするために、エリカはそうです)。

struct TestModal: View {
    @State var isPresented: Binding<Bool>

    var body: some View {
        Button(action: { self.isPresented.value = false }, label: { Text("Done") })
    }
}

struct ContentView : View {
    @State var modalPresented = false

    var body: some View {
        NavigationView {
            Text("Hello World")
            .navigationBarTitle(Text("View"))
            .navigationBarItems(trailing:
                Button(action: { self.modalPresented = true }) { Text("Show Modal") })
        }
        .presentation(self.modalPresented ? Modal(TestModal(isPresented: $modalPresented)) {
            self.modalPresented.toggle()
        } : nil)
    }
}
1
Brad

@Environment(\.presentationMode) var presentationModeを使用して、前のビューに戻ります。詳細については、以下のコードを確認してください。

import SwiftUI

struct ContentView: View {


    var body: some View {

        NavigationView {
            ZStack {
                Color.gray.opacity(0.2)

                NavigationLink(destination: NextView(), label: {Text("Go to Next View").font(.largeTitle)})
            }.navigationBarTitle(Text("This is Navigation"), displayMode: .large)
                .edgesIgnoringSafeArea(.bottom)
        }
    }
}

struct NextView: View {
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2)
        }.navigationBarBackButtonHidden(true)
            .navigationBarItems(leading: Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }, label: { Image(systemName: "arrow.left") }))
            .navigationBarTitle("", displayMode: .inline)
    }
}


struct NameRow: View {
    var name: String
    var body: some View {
        HStack {
            Image(systemName: "circle.fill").foregroundColor(Color.green)
            Text(name)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
0
Ashish Kanani

Xcode 11.3

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

...

// If animation is strange, try this.
DispatchQueue.main.async {
    self.presentationMode.wrappedValue.dismiss()
}
0
hstdt

navigationButtonの代わりにNavigation DestinationLinkを使用します

しかし、あなたは結合をインポートする必要があります

struct AView: View {
 var link: NavigationDestinationLink<BView>
var publisher: AnyPublisher<Void, Never>

init() {
    let publisher = PassthroughSubject<Void, Never>()
    self.link = NavigationDestinationLink(
        BView(onDismiss: { publisher.send() }),
        isDetail: false
    )
    self.publisher = publisher.eraseToAnyPublisher()
}

var body: some View {
    NavigationView {
        Button(action:{
        self.link.presented?.value = true


 }) {
            Text("Go to B")
        }.onReceive(publisher, perform: { _ in
            self.link.presented?.value = false
        })
    }
}
}

struct BView: View {
var onDismiss: () -> Void
var body: some View {
    Button(action: self.onDismiss) {
        Text("Come back to A")
    }
}
}
0
Alireza12t