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()
}