lucaszischka/BottomSheet

iOS 17.0 Unexpected Animation Behavior

Opened this issue · 4 comments

Describe the bug
With devices and simulators running iOS 17.0, the bottom bottom sheet animates from the top left to the bottom when the view appears. This is only preventable when setting the custom animation to nil. This results in an undesirable animation when the bottom sheet appears. However, with the animation value of nil the bottom sheet will end up janky transition on resize.

Minimal reproduce-able code
Using the default values for the .bottomSheet modifier and an animation value other than nil.

Expected behavior
I would expect only the resizing of the bottom sheet to animate, not the entire sheet itself (especially on appear).

Screenshots
N/a.

Target version

  • Environment: iOS
  • Version: 17.0

Additional context
Works as expected in iOS 16.4.

You can work around this issue by using nil as your initial animation value and set it to an actual animation value on onAppear (for example).

Thanks for your response. This is in fact the solution I went with in the end and found it be working well.

Thanks for the solution guys - in attempting to reproduce the fix, I couldn't see a change in the animation when setting the customAnimation after the onAppear. Am I missing something?

struct BookDetailView: View {
    @State var bottomSheetPosition: BottomSheetPosition = .hidden
    @State var animationValue:Animation? = nil
    
    let backgroundColors: [Color] = [Color(red: 0.2, green: 0.85, blue: 0.7), Color(red: 0.13, green: 0.55, blue: 0.45)]
    let readMoreColors: [Color] = [Color(red: 0.70, green: 0.22, blue: 0.22), Color(red: 1, green: 0.32, blue: 0.32)]
    let bookmarkColors: [Color] = [Color(red: 0.28, green: 0.28, blue: 0.53), Color(red: 0.44, green: 0.44, blue: 0.83)]
    
    var body: some View {
        ZStack(content: {
            

        //A green gradient as a background that ignores the safe area.
        LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
        
            
            
            VStack(alignment: .center, spacing: 30, content: {
                Button(action: {
                    self.bottomSheetPosition = .dynamic
                }, label: {
                    Text("Show detail sheet")
                })
            })
            .edgesIgnoringSafeArea(.all)
            .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, switchablePositions: [
                .dynamic, .hidden
            ], content: {
                //A short introduction to the book, with a "Read More" button and a "Bookmark" button.
                VStack(spacing: 0) {
                    Text("This tumultuous tale of life in a bleak farmhouse on the Yorkshire moors is a popular set text for GCSE and A-level English study, but away from the demands of the classroom it’s easier to enjoy its drama and intensity. Populated largely by characters whose inability to control their own emotions...")
                        .fixedSize(horizontal: false, vertical: true)
                    
                    HStack {
                        Button(action: {}, label: {
                            Text("Read More")
                                .padding(.horizontal)
                        })
                            .buttonStyle(BookButton(colors: self.readMoreColors)).clipShape(Capsule())
                        
                        Spacer()
                        
                        Button(action: {}, label: {
                            Image(systemName: "bookmark")
                        })
                            .buttonStyle(BookButton(colors: self.bookmarkColors)).clipShape(Circle())
                    }
                    .padding(EdgeInsets(top: 30, leading: 0, bottom: 30, trailing: 0))
                    
                    
                }
                .padding([.horizontal, .top])
                .onAppear {
// Set the animation value here
                    self.animationValue = .linear.speed(1)
                }
            })
            .showDragIndicator(true)
            .enableContentDrag()
            .showCloseButton()
            .enableSwipeToDismiss()
            .enableTapToDismiss()
            .customThreshold(0.1)
            .customAnimation(self.animationValue)
        })
        
    }
}

@timstewardship

You can use the Task Modifier while adding a Task.sleep().
Something like this:

            .task {
				try? await Task.sleep(for: .seconds(0.25))
				animationValue = .linear.speed(1)
            }

This will let the View render properly and then apply your animation without running into weird Animation issues.