search
LoginSignup
0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

SwiftUIでBottomBarが消えるバグを回避する

BottomBarが消えるバグが存在する

SwiftUIは、BottomBarのアイテムが消える既知のバグが存在する。
発生条件は以下の通りである。

発生条件

  • iOS14.4(執筆時の最新OS)
  • ListのContentにNavigationLinkを指定している
  • 「親階層→子階層→孫階層→子階層→親階層」の順に画面遷移

RocketSim Recording - iPhone 12 Pro Max - 2021-02-21 16.14.13.gif

バグが発生してしまうコード

BottomBarが消える
struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink(
                    destination: ChildView(),
                    label: {
                        Text("Parent")
                    })
            }
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("Item")
                }
            }
            .navigationTitle("バグ発生")
        }
    }
}

struct ChildView: View {
    var body: some View {
        NavigationLink(
            destination: Text("Grandchild"),
            label: {
                Text("Child")
            })
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("Item")
                }
            }
    }
}

解決策1:idインスタンスメソッドを活用

StackOverflowに解決策として記載されていました。

idインスタンスメソッドとは?

プロキシ値が更新された場合、画面を再描画します。

idインスタンスメソッドを活用した解決策

idを活用
struct ContentView: View {
    @State var refresh = UUID()  // ← 固有識別番号を割り当てる
    var body: some View {
        NavigationView {
            List {
                NavigationLink(
                    destination: ChildView(),
                    label: {
                        Text("Parent")
                    })
            }
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("Item")
                }
            }
            .navigationTitle("バグ発生")
            .id(refresh)  // ← 子と孫階層の再描画を防ぐ
        }
    }
}

解説

StackOverflowの解説によると、

描画タイミングを自明にすることで子階層の強制再描画を防ぐ

引用元:swiftUI bottomBar toolbar disappears when going back

と書いていた。しかし、私の環境はバグを回避することができませんでした。一応、StackOverflowの有識者がバグの回避策として提言されていたため、執筆しました。

解決策2:ListのContentにNavigationLinkを宣言しない

バグの発生条件として、「ListのContentにNavigationLinkを指定している」が存在する。そのため、ContentNavigationLinkを指定しなければバグが発生しない。

Contentに宣言せず、遷移処理を実装する

isActionを使うよ
struct ContentView: View {
    @State var transition = false
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(
                    destination: ChildView(),
                    isActive: $transition,
                    label: {})
                List {
                    Button(action: {
                        transition.toggle()
                    }, label: {
                        Text("Parent")
                    })
                }
            }
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("Item")
                }
            }
            .navigationTitle("バグ回避")
        }
    }
}

RocketSim Recording - iPhone 12 Pro Max - 2021-02-21 16.47.53.gif

解説

NavigationLinkisActiveを用いて遷移処理を実装します。labelパラメーターを宣言しない状態だと、画面にアイテムが描画しない状態でNavigationLinkを宣言することができます。そしてVStack(or HStack)Buttonとセットにしなければエラーの原因になるので、注意が必要です。

注意

この解決策はガイドラインに則っていません。また、コードも汚いです。

最後に

今回はBottomBarが消えるバグの回避策を執筆しました。ガイドラインに適さない手法で実装しており、褒められた手段ではありません。
他の手段もしくは記事に間違いがある場合、コメント欄で指導してくださると幸いです。

参考サイト

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0
Help us understand the problem. What are the problem?