🎸

SwiftUIのLinearGradientの仕様がiOS15とそれ以上で違った

2023/12/22に公開

はじめに

こんにちは。最近自宅用に4Lのウィスキーと焼酎を買った住山です。私の開発するアプリで↓のようにメニューの右端が徐々に薄くなるViewを実装したらiOS15とそれ以上で見た目が変わったので共有です。LinearGradientのColor: [.clear, .white]で実装したところ、2色のグラデーション部分の間に黒い部分が入ってしまう不具合が発生した。

不具合の起きた実装

当初の実装はこのようにSwiftUI標準のLinearGradientを使った。

struct ContentView: View {
    let texts = ["春はあけぼの", "夏は夜", "秋は夕暮れ", "冬はつとめて"]

    var body: some View {
        HStack {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    ForEach(texts, id: \.self) { text in
                        Text(text)
                            .font(.headline)
                            .frame(width: 100)
                    }
                }
            }
            .overlay {
                LinearGradient(gradient: Gradient(colors: [.clear, .white]),
                               startPoint: UnitPoint(x: 0.8, y: 0.5),
                               endPoint: .trailing)
                .allowsHitTesting(false)
            }

            Button(action: {},
									 label: {
                Image(systemName: "slider.horizontal.3")
            })
        }
        .padding()
    }
}

iOS16~ 想定通りの動作

iOS15 右端に黒い影入る

不具合修正

colors: [Color]で.clearを指定していたところを.white.opacity(0)に修正した。

LinearGradient(gradient: Gradient(colors: [.white.opacity(0), .white]),
                                  startPoint: UnitPoint(x: 0.8, y: 0.5),
                                  endPoint: .trailing)

iOS15

コード全文

struct ContentView: View {
    let texts = ["春はあけぼの", "夏は夜", "秋は夕暮れ", "冬はつとめて"]

    var body: some View {
        HStack {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    ForEach(texts, id: \.self) { text in
                        Text(text)
                            .font(.headline)
                            .frame(width: 100)
                    }
                }
            }
            .overlay {
                LinearGradient(gradient: Gradient(colors: [.white.opacity(0), .white]),
                               startPoint: UnitPoint(x: 0.8, y: 0.5),
                               endPoint: .trailing)
                .allowsHitTesting(false)
            }

            Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/,
                   label: {
                Image(systemName: "slider.horizontal.3")
            })
        }
        .padding()
    }
}

まとめ

おそらくiOS15のColor.ClearはColor.Black.opacity(0)で表現されていたため上記のような不具合が発生していたと思います。。(試しに、iOS15でLinearGradient(colors: [.black.opacity(0), .white])を試したら、[.clear, .white]と同じViewになった)iOS15とそれ以降でColor.clearでの挙動が違うので使う時は注意した方がよさそうです。

株式会社ガラパゴス(有志)

Discussion