0

I am trying to apply .glassEffect to some controls that are in a horizontal scroll view in a bottom .safeAreaBar.

No matter what I try, there is a persistent pesky flickering of the background that I can't get rid of. It happens when swiping left in the bottom safe area bar to access the next set of controls.

So far, I tried:

  • Wrapping either controls or the stacks in GlassEffectContainer
  • Removing .interactive() from glass effects
  • .drawingGroup() (incompatible with glass effects)
  • .compositingGroup() and .geometryGroup() change nothing
  • Tuning spacing/margins (only partially helped)

Removing the .glassEffect() from all controls fixes the flicker, but I want to use it to keep it consistent with other controls present on screen.

Any suggestions?

Here's the reproducible code and a screen recording:

import SwiftUI

struct GlassEffectScrollTest: View {
    // Mock state
    @State private var selectedOption1: MockOption = .option1
    @State private var selectedOption2: MockOption = .optionA
    @State private var value1: Double = 12
    @State private var value2: Double = 20
    @State private var showHighlight: Bool = false

    var body: some View {
        NavigationStack {
            if #available(iOS 26.0, *) {
                ScrollView {
                    VStack(spacing: 0) {
                        ForEach(0..<50, id: \.self) { index in
                            VStack(alignment: .leading, spacing: 8) {
                                Text("Item \(index + 1)")
                                    .font(.headline)
                                Text("This is some sample content that will scroll beneath the toolbar. The toolbar should maintain a soft edge blur effect as this content scrolls underneath it.")
                                    .font(.subheadline)
                                    .foregroundStyle(.secondary)
                                    .fixedSize(horizontal: false, vertical: true)
                            }
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .padding()
                            .background(Color(.systemBackground), in: .rect(cornerRadius: 12))
                            .padding(.horizontal)
                            .padding(.vertical, 6)
                        }
                    }
                    .padding(.top)
                }
                .background(Color(.systemGroupedBackground))
                .safeAreaBar(edge: .bottom) {
                    mockToolbar()
                }
                .navigationTitle("Glass Effect Test")
            } else {
                // Fallback on earlier versions
            }
        }
    }

    @ViewBuilder
    private func mockToolbar() -> some View {
        if #available(iOS 26.0, *) {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 24) {
                    // Section 1: Font controls mockup
                    HStack(spacing: 16) {
                        Picker("Option 1", selection: $selectedOption1) {
                            ForEach(MockOption.allCases) { option in
                                Text(option.rawValue).tag(option)
                            }
                        }
                        .pickerStyle(.menu)
                        .labelsHidden()
                        .fixedSize()
                        .controlSize(.small)
                        .glassEffect(.clear, in: .capsule)

                        Toggle(isOn: $showHighlight) {
                            Image(systemName: "highlighter")
                                .contentTransition(.symbolEffect(.replace))
                                .font(.subheadline)
                                .foregroundStyle(.tint)
                        }
                        .toggleStyle(.button)
                        .tint(.yellow)
                        .glassEffect(.clear, in: .capsule)

                        Spacer()

                        Text("\(Int(value1))pt")
                            .foregroundStyle(.secondary)
                            .font(.subheadline)
                            .frame(minWidth: 35, alignment: .trailing)

                        Stepper("", value: $value1, in: 8...32, step: 1)
                            .labelsHidden()
                            .fixedSize()
                            .controlSize(.small)
                            .glassEffect(.clear, in: .capsule)
                    }
                    .containerRelativeFrame(.horizontal)

                    // Section 2: Spacing controls mockup
                    HStack(spacing: 16) {
                        Picker("Option 2", selection: $selectedOption2) {
                            ForEach(MockOption.allCases) { option in
                                Text(option.rawValue).tag(option)
                            }
                        }
                        .pickerStyle(.menu)
                        .fixedSize()
                        .labelsHidden()
                        .glassEffect(.clear, in: .capsule)

                        Spacer()

                        Text("\(Int(value2))pt")
                            .foregroundStyle(.secondary)
                            .font(.subheadline)
                            .frame(minWidth: 35, alignment: .trailing)

                        Stepper("", value: $value2, in: 0...50, step: 2)
                            .labelsHidden()
                            .glassEffect(.clear, in: .capsule)
                    }
                    .containerRelativeFrame(.horizontal)
                }
                .scrollTargetLayout()
            }
            .scrollTargetBehavior(.viewAligned)
            .scrollContentBackground(.hidden)
            .padding(.vertical, 20)
            .contentMargins(.horizontal, 24, for: .scrollContent)
            .containerRelativeFrame(.horizontal)
            .overlay(alignment: .bottom) {
                Text("Swipe horizontally for more tools \(Image(systemName: "hand.draw.fill"))")
                    .font(.caption2)
                    .foregroundStyle(.tertiary)
                // .padding(.bottom, 4)
                    .padding(.top, 10)
            }
        }
    }
}

// Mock data
enum MockOption: String, CaseIterable, Identifiable {
    case option1 = "Option 1"
    case option2 = "Option 2"
    case option3 = "Option 3"
    case optionA = "Option A"
    case optionB = "Option B"
    case optionC = "Option C"

    var id: String { rawValue }
}

#Preview {
    GlassEffectScrollTest()
}

enter image description here

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.