0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUI GeometryReaderで囲ったViewに重なってしまった時の対処方法

Last updated at Posted at 2025-10-18

目的

GeometryReaderで囲ったViewのHeightが固定値であれば、そのViewのHeightと同じ値をGeometryReaderのHeightに設定することで解決できる。

GeometryReaderで囲ったViewのHeightが可変である時、Viewの高さが決まってからGeometryReaderのHeightに反映させる必要がある。
その方法を自分用にメモしておきます。

問題のコード

struct ContentView: View {
    var body: some View {
        ScrollView {
            blueView
            redView
        }
    }
    
    private var blueView: some View {
        GeometryReader { geometry in
            Rectangle()
                .frame(maxWidth: .infinity)
                .frame(height: geometry.size.width / 2)
                .foregroundStyle(.blue)
        }
    }
    
    private var redView: some View {
        Rectangle()
            .frame(maxWidth: .infinity)
            .frame(height: 100)
            .foregroundStyle(.red)
    }
}

上記のコードでの表示内容は以下です。

解決したコード

struct ContentView: View {
    // ↓↓ ①追加
    @State var blueViewHeight: CGFloat = 0
    
    var body: some View {
        ScrollView {
            blueView
            redView
        }
    }
    
    private var blueView: some View {
        GeometryReader { geometry in
            Rectangle()
                .frame(maxWidth: .infinity)
                .frame(height: geometry.size.width / 2)
                .foregroundStyle(.blue)
                // ↓↓ ④追加
                .background {
                    GeometryReader { blueViewGeometry in
                        Color.clear
                            .preference(
                                key: BlueViewHeightKey.self,
                                value: blueViewGeometry.size.height
                            )
                    }
                }
        }
        // ↓↓ ②追加
        .frame(height: blueViewHeight)
        // ↓↓ ⑤追加
        .onPreferenceChange(BlueViewHeightKey.self) { height in
            blueViewHeight = height
        }
    }
    
    private var redView: some View {
        Rectangle()
            .frame(maxWidth: .infinity)
            .frame(height: 100)
            .foregroundStyle(.red)
    }
}

// ↓↓ ③追加
struct BlueViewHeightKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {}
}

上記のコードでの表示内容は以下です。

説明

① 確定した青いViewのHeightを格納するための変数です。

② 確定した青いViweのHeightをGeometryReaderのHeightに反映させています。

③ このKeyで確定した青いViewのHeightを流して、同じKeyで取得するために用意します。

④ backgroundでGeometryReaderを使うことで、青いViewのgeometryが取得できます。
このgeometryから確定した青いViewのHeightが取得できます。
Color.clearは③で作成したKeyを監視しているところに値を流すためのpreferenceをつけるためのものです。
そのため表示に影響しないColor.clearを使用しています。

⑤ ③で作成したKeyで流れてきた値を監視して①の変数に反映します。

※あくまで個人的な理解ですので間違えていたらすみません。
もっと推奨されるやり方があったらご教授頂けると助かります!

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?