I’m building a reusable custom bottom sheet component in SwiftUI because my app supports iOS 15, so I can’t use .sheet with detents yet. Functionally everything works the sheet opens and closes but I’m running into a visual glitch:

Problem

When the bottom sheet animates in or out, I see a brief flicker or fade of the underlying content beneath the sheet. It looks like the previous frame of the view is fading through before the animation finalizes. This only lasts a fraction of a second but is very noticeable.

Can someone help me take a look at whats happening? The code I provided should be easy enough to copy and paste into a barebone project:

import SwiftUI enum BottomSheetType: CaseIterable { case boxImage case normal } struct ContentView: View { @StateObject private var viewModel = BottomSheetViewModel() var body: some View { ZStack { Text("Show Bottom Sheet") .padding() .background(Capsule().stroke()) .onTapGesture(perform: viewModel.toggle) if viewModel.isPresented { ZStack(alignment: .bottom) { VStack { Spacer() // The part that's going to be reusable VStack(spacing: 0) { switch viewModel.type { case .boxImage: ListModal(viewModel: viewModel) case .normal: NormalModal() case .none: EmptyView() } } .padding(.bottom, 30) .frame(maxWidth: .infinity) .background(Color(.systemGray6)) .cornerRadius(20) } } .transition(.move(edge: .bottom)) .scaleEffect(1) } } .ignoresSafeArea() } } struct ListModal: View { var viewModel: BottomSheetViewModel var body: some View { ForEach(viewModel.items.indices, id: \.self) { index in let genre = viewModel.items[index] Text(genre) .font(.title2) .frame(height: 30) } } } struct NormalModal: View { var body: some View { VStack(spacing: 20) { Text("Heading 1") .font(.largeTitle) .frame(height: 30) Text("Heading 2") .font(.title) .frame(height: 30) Text("Heading 3") .font(.title2) .frame(height: 30) } .padding(.top, 20) } } final class BottomSheetViewModel: ObservableObject { var type: BottomSheetType? @Published var isPresented: Bool = false var items: [String] = [] func generateRandomItems() { type = BottomSheetType.allCases.randomElement()! let count = Int.random(in: 5...10) items = (5...count).map { "Item \($0)" } } func toggle() { generateRandomItems() withAnimation(.spring()) { isPresented.toggle() } } }

DarkBee's user avatar

DarkBee

14.5k9 gold badges84 silver badges133 bronze badges

K. Janjuha's user avatar

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.