SwiftUIで2つ以上前の画面へ戻る方法

NavigationView・NavigationLink での階層的な画面遷移で、1つ前の画面へプログラムで戻る方法についてはこちらの記事で紹介しました。では、2つ以上の階層があるアプリケーションで、一気に最初の画面へ戻るにはどのようにしたら良いでしょうか。

UIKitで言うところのpopToRootViewControllerをSwiftUIでやってみようと思います。

SwiftUIで2つ以上前の画面へ戻る方法

今回ポイントとなるのは@State@Bindingです。

@Stateを付与すると、紐付けたView要素の状態を監視し、値が変化すると、再描画などを自動的に行ってくれるようになります。

@Bindingは、別画面の値を関連付けることができ、例えば、A画面のViewで宣言したBool値を、B画面で@Bindingを付与した変数で受け取ることで、B画面でそのBool値が変化した際に、A画面でもその変化を検知することが出来ます。

では実際にコード例を見ていきます。

実装コード例

First View

struct FirstView: View {
    
    @State private var isActive = false
    
    var body: some View {
        NavigationView {
            NavigationLink(destination: SecondView(isFirstViewActive: $isActive), isActive: $isActive) {
                Button(action: {
                    self.isActive = true
                }, label: {
                    Text("Forward to Second View.")
                })
            }
            .navigationBarTitle("First View")
        }
    }
}

@Stateで宣言した変数をNavigationLinkの isActive: に $isActive として紐付けていて、Buttonを押下した際にtrueとなり、Second Viewへ遷移するようになっています。

その際、Second Viewのイニシャライザーの isFirstViewActive: にも $isActive として遷移先画面の変数(@Binding)に関連付けをしています。

Second View

struct SecondView: View {
    
    @State private var isActive = false
    @Binding var isFirstViewActive: Bool
    
    var body: some View {
        NavigationLink(destination: ThirdView(isFirstViewActive: $isFirstViewActive), isActive: $isActive) {
            Button(action: {
                self.isActive = true
            }, label: {
                Text("Forward to Third View.")
            })
        }.isDetailLink(false)
        .navigationBarTitle("Second View")
    }
}

続いて、Second View ですが、先ほどの First View で Second View のイニシャライザーに $isActive を指定していましたが、その受け皿になっているのが、@Bindingを付与した isFirstViewActive 変数です。

FirstView の isActive と Second View の isFirstViewActive が関連付けされたことになります。

そして、何よりも大事なポイントが isDetailLink(false) の部分です。これがないと First View の isActive が Second View 止まりとなってしまい、Third View への紐付けが出来ません。

Third View への遷移は First View から Second View への遷移方法と全く同じです。

Third View

struct ThirdView: View {
    
    @Binding var isFirstViewActive: Bool
    
    var body: some View {
        Button(action: {
            self.isFirstViewActive = false
        }, label: {
            Text("Back to First View.")
        })
        .navigationBarTitle("Third View")
    }
}

最後に、Third View です。

同じく、@Binding を付与した isFirstViewActive が宣言されており、Second View から Third View への遷移時のイニシャライザーで関連付けがされています。

そして、Button が押下された際に、isFirstViewActive を false とすることで、First View の NavigationLink が解除され、Third View から一気に First View へ戻る挙動が実現出来ます。

ちなみに、更に次の画面(Fourth View)がある場合は、Third View にも NavigationLinkisDetailLink(false) が必要になります。

実際、より階層が深くなるアプリケーションだと少々冗長になりそうですが、一旦はこの方法しかわからないので、どなたか詳しい方おりましたらご指摘ください。

以上

コメントを残す

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