5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-02-21

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

参考サイト

5
0
0

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
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?