Home > Software engineering >  SwiftUI Button content uses its own animation where it shouldn't
SwiftUI Button content uses its own animation where it shouldn't

Time:12-21

I have a custom transition to present/dismiss a custom sheet. My problem is that the button content is using its own animation, where it should just follow the rest:

See how the "OK" button is jumping to the bottom in the dismiss animation. It should just be following the rest of the sheet.

Full code:

import SwiftUI

@main
struct SwiftUITestsApp: App {
    var body: some Scene {
        WindowGroup {
            SheetButtonAnimationTestView()
        }
    }
}

struct SheetButtonAnimationTestView: View {
    @State private var sheetPresented = false
    
    var body: some View {
        ZStack(alignment: .bottom) {
            Button("Present sheet", action: { sheetPresented = true })
                .frame(maxWidth: .infinity, maxHeight: .infinity)

            if sheetPresented {
                Sheet(title: "Sheet", dismiss: { sheetPresented = false })
                    .transition(.move(edge: .bottom))
            }
        }
        .animation(.easeOut(duration: 2), value: sheetPresented)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.white.edgesIgnoringSafeArea(.all))
    }
}


struct Sheet: View {
    var title: String
    var dismiss: () -> ()
        
    var body: some View {
        VStack(spacing: 16) {
            HStack {
                Text(title)
                    .foregroundColor(.white)
                
                Spacer()
                
                Button(action: dismiss) {
                    Text("OK").font(.headline.bold()).foregroundColor(.blue)
                        .padding(10)
                        .background(Capsule().fill(Color.white))
                }
            }

            Text("This is the sheet content")
                .foregroundColor(.white)
                .frame(height: 300)
                .frame(maxWidth: .infinity)
        }
        .padding(24)
        .frame(maxWidth: .infinity)
        .background(
            Rectangle().fill(Color.black).edgesIgnoringSafeArea(.bottom)
        )
        .ignoresSafeArea(.container, edges: .bottom) // allows safe area for keyboard
    }
    
}

How to make the button follow the sheet animation?

Tested on iOS 16.0.3, iPhone 11, XCode 14.1

CodePudding user response:

Seems like a bug in the library. You can add a slight delay in the button action, which will solve the issue:

Button(action: {
   DispatchQueue.main.asyncAfter(deadline: .now()   0.001) {
      dismiss()
   }
}) {
   Text("OK").font(.headline.bold()).foregroundColor(.blue)
      .padding(10)
      .background(Capsule().fill(Color.white))
}

Or if you don't want the click animation, you can remove the button and do the following:

Text("OK").font(.headline.bold()).foregroundColor(.blue)
   .padding(10)
   .background(Capsule().fill(Color.white))
   .onTapGesture {
      dismiss()
   }
  • Related