SwiftUIでNavigationLinkが一度しか動作しない問題

NavigationView / NavigationLinkを使おうとして、思わぬところで不具合らしきものにハマってしまったので、その原因とワークアラウンドを記す。

2020.11.19追記: Xcode 12のSwiftUIで、こちらの問題が修正されていることを確認できた。

SwiftUIでUINavigationController的なUIを実装するときは、NavigationViewとNavigationLinkを使う。

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: Text("Detail")) {
                Text("Show")
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

上のコードを実行すると、このような実行画面になる。

最初の画面に現れるShowの文字をクリックすると、Detail画面が出現する。そして、画面左上の戻るボタン(<)をクリックすると、元の画面に戻ることができる。

しかし、Xcode 11.3でコンパイルしたアプリでは、元の画面に戻った後再びShowの文字をクリックしても、Detail画面に画面が遷移しない。最初は、NavigationLinkの問題かと思っていたが、調べてみたらどうやら戻るボタンの方に不具合があるのではないか、という情報を見つけた。

実際に試してみたところ、戻るボタンを使わずに前の画面に遷移した場合は、戻った後にShowをクリックして正常にDetail画面に遷移できることが確認された。

上記記事にもサンプルコードの記載がある通り、NavigationLinkを直接使って遷移するのではなく、isActiveフラグを使って遷移を制御する形にすることで、この問題を回避できる。

struct ContentView: View {
    @State private var showDetailView: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination:
                    VStack {
                        Text("Detail")
                        Button(action: {
                            self.showDetailView = false
                        }) {
                            Text("Back")
                        }
                    }
                    .navigationBarBackButtonHidden(true)
                , isActive: $showDetailView) {
                    EmptyView()
                }
                Button(action: {
                    self.showDetailView = true
                }) {
                    Text("Show")
                }
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

参考:

Pocket

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です