lucaszischka / BottomSheet

A sliding Sheet from the bottom of the Screen with 3 States build with SwiftUI.
MIT License
1.06k stars 137 forks source link

Swiping on mainContent dismisses it… Without dismissing the sheet. #58

Closed Rheaparks closed 2 years ago

Rheaparks commented 2 years ago

Hello,

As I was testing "swiping to dismiss" in the simulator I've found what I believe is a bug. Indeed, when I swipe the sheet the main content dismisses itself with an animation while the rest of the sheet stays in place.

The problem can be reproduced with the .swipeToDismiss option, as well as without it.

Examples

With swipeToDismiss

https://user-images.githubusercontent.com/73537538/159232791-4a3a02bf-b804-4e72-85c2-aa7f489310eb.mov

Without the option

https://user-images.githubusercontent.com/73537538/159233151-cfffd681-69f2-4f52-bb90-3cc4314285db.mov

Sample Code

This is mostly the Book Detail View example taken straight from the README.

import SwiftUI
import BottomSheet

//The custom BottomSheetPosition enum with absolute values.
enum BookBottomSheetPosition: CGFloat, CaseIterable {
    case middle = 300
    case bottom = 299.999
    case hidden = 0
}

struct ContentView: View {

    @State var bottomSheetPosition: BookBottomSheetPosition = .middle

    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 {
        //A green gradient as a background that ignores the safe area.
        LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)

            .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, options: [.noDragIndicator, .allowContentDrag, .showCloseButton(), .swipeToDismiss, .tapToDismiss, .absolutePositionValue], headerContent: {
                //The name of the book as the heading and the author as the subtitle with a divider.
                VStack(alignment: .leading) {
                    Text("Wuthering Heights")
                        .font(.title).bold()

                    Text("by Emily Brontë")
                        .font(.subheadline).foregroundColor(.secondary)

                    Divider()
                        .padding(.trailing, -30)
                }
            }) {
                //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(.top)

                    Spacer(minLength: 0)
                }
                .padding([.horizontal, .top])
            }
    }
}

//The gradient ButtonStyle.
struct BookButton: ButtonStyle {

    let colors: [Color]

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.headline)
            .foregroundColor(.white)
            .padding()
            .background(LinearGradient(gradient: Gradient(colors: self.colors), startPoint: .topLeading, endPoint: .bottomTrailing))
    }
}

Configuration

Xcode 13.3 iOS 15.4 iPhone 13 mini simulator

lucaszischka commented 2 years ago

This ‚bug‘ comes down to this part in your example code:

case middle = 300
case bottom = 299.999

I can explain to you what happens:

  1. You are in the .middle position at the beginning.
  2. You swipe down on the BottomSheet.
  3. Now you are in the .bottom position
    • Because the .middle and .bottom values are nearly the same you don’t see a different
    • Nevertheless the main content gets hidden in the .bottom position (see Documentation); to prevent this use the.noBottomPosition option.
    • The bottom sheet however is still on screen.
  4. Now you swipe again and the BottomSheet gets dismissed.

This is everything as expected. If you change the .bottom position value to something smaller (like 150), you will probably understand the behavior.

This has indeed nothing to do with the .swipeToDismiss option, but with your values of the BottomSheetPostion enum.

If it is still unclear to you, please read the README.MD again.