[SwiftUI]ScrollViewの副作用を抑制する


0. 概要

SwiftUIのScrollViewには副作用があり、ビューの配置の仕方によって周囲のビューの動作が決定します。
例えば、次のようなコードはScrollViewの中のTextのみならずNaviagtionのタイトルも連動してスクロールするようになります。

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("view")
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.large)
        }
    }
}

Simulator Screen Recording - iPhone 13 mini - 2021-11-21 at 16.54.13.gif

この挙動はiOSの標準的な挙動なので悪戯に無効化する必要はありませんが、どうしても無効化したい場合次のようなワークアラウンドがあります。

ワークアラウンド

ScrollViewの副作用は

  1. NavigationViewのルートにScrollViewが配置されている
  2. ScrollViewが親ビューの上部に隣接している

ことで発生するため、これらを回避することで副作用を抑制させることができます。

struct ContentView: View {
    var body: some View {
        NavigationView {
            ZStack(alignment: .top) {
                Rectangle().foregroundColor(.white) // 1
                ScrollView {
                    Text("view")
                }.offset(y: 1) // 2
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.large)
        }
    }
}

1で間に挟むビューは一定の不透明度が必要なため、.clearやopacity(0)を使うことはできません。