Home > database >  Bottom Sheet causing parent view to shift
Bottom Sheet causing parent view to shift

Time:11-13

I have a bottom sheet that I toggle on and off. When I go to close out the view, I noticed the parent view shifts. I've tried adjusting the variables and couldn't find the culprit.

I have suspicion the issue is occurring on .gesture at the end of the bottom sheet class but I'm not sure. Is there anyway to stop the parent view from shifting when toggled?

BottomSheet

fileprivate enum Constants {
    static let radius: CGFloat = 16
    static let indicatorHeight: CGFloat = 6
    static let indicatorWidth: CGFloat = 60
    static let snapRatio: CGFloat = 0.25
    static let minHeightRatio: CGFloat = 0.3
}

struct BottomSheetView<Content: View>: View {
    @Binding var isOpen: Bool

    let maxHeight: CGFloat
    let minHeight: CGFloat
    let content: Content

    @GestureState private var translation: CGFloat = 0

    private var offset: CGFloat {
        isOpen ? 0 : maxHeight - minHeight
       
    }

    private var indicator: some View { // << toggling while open
        RoundedRectangle(cornerRadius: Constants.radius)
            .fill(Color.secondary)
            .frame(
                width: Constants.indicatorWidth,
                height: Constants.indicatorHeight
        ).onTapGesture {
            self.isOpen.toggle()
        }
    }

    init(isOpen: Binding<Bool>, maxHeight: CGFloat, @ViewBuilder content: () -> Content) {
        self.minHeight = maxHeight * Constants.minHeightRatio
        self.maxHeight = maxHeight
        self.content = content()
        self._isOpen = isOpen
    }

    var body: some View {
        GeometryReader { geometry in
            VStack(spacing: 0) {
                self.indicator.padding()
                self.content
            }
            .frame(width: geometry.size.width, height: self.maxHeight, alignment: .top)
            .background(Color(.secondarySystemBackground))
            .cornerRadius(Constants.radius)
            .frame(height: geometry.size.height, alignment: .bottom)
            .offset(y: max(self.offset   self.translation, 0))
            .animation(.interactiveSpring())
            .gesture(
                DragGesture().updating(self.$translation) { value, state, _ in
                    state = value.translation.height
                }.onEnded { value in
                    let snapDistance = self.maxHeight * Constants.snapRatio
                    guard abs(value.translation.height) > snapDistance else {
                        return
                    }
                    self.isOpen = value.translation.height < 0
                }
            )
        }
    }
}

View

  struct TestView2: View {
   
    @State private var showMenu = false
    @State var deleteAccountSheet = false
  
    var body: some View {
            NavigationView{
                VStack{
                   Text("click me")
                        .onTapGesture{
                            deleteAccountSheet = true
                        }
                    HStack{
                        Text( "this will move up in view" )
                            .font(.custom("OpenSans-Regular", size: 24))
                    }
                    Text("in the view")
                    
                }
                
            
            }
            .blur(radius: deleteAccountSheet ? 2 : 0) // blur when bottomsheet open
                GeometryReader { geometry in {
                    BottomSheetView(
                        isOpen: self.$deleteAccountSheet,
                        maxHeight: geometry.size.height * 0.7
                    ) {
                        Text("Give me one more click")
                            .onTapGesture{
                                print("click")
                                self.deleteAccountSheet = false
                            }
                    }
                   
                }().edgesIgnoringSafeArea(.all)
                       
                }
            }
             
        }

CodePudding user response:

The VStack containing the text was being laid out vertically with the bottom sheet. You can use a ZStack to make sure that the bottom sheet is laid out on top of the VStack containing text.

The height of the VStack containing the text and the GeometryReader is equal, this means the value of geometry.size.height is really fullScreenHeight * 0.5 * 0.7.

If the contents of the NavigationView is nested in a ZStack the geometry.size.height will be the full height of the screen in this case. Changing from maxHeight: geometry.size.height * 0.7 to maxHeight: geometry.size.height * 0.5 * 0.7 will give you the same sizing of the bottom sheet that you had in the example you provided. Here's an example of how to update the View which displays the bottom sheet to get this working:

struct TestView: View {

    @State private var showMenu = false
    @State var deleteAccountSheet = false

    var body: some View {
        NavigationView{
            ZStack {
                VStack {
                    Text("click me")
                        .onTapGesture{
                            deleteAccountSheet = true
                        }
                    HStack{
                        Text( "this will move up in view" )
                            .font(.custom("OpenSans-Regular", size: 24))
                    }
                    Text("in the view")
                }
                .blur(radius: deleteAccountSheet ? 2 : 0)

                GeometryReader { geometry in
                    BottomSheetView(
                        isOpen: self.$deleteAccountSheet,
                        maxHeight: geometry.size.height * 0.5 * 0.7
                    ) {
                        Text("Give me one more click")
                            .onTapGesture{
                                print("click")
                                self.deleteAccountSheet = false
                            }
                    }
                }
                .edgesIgnoringSafeArea(.all)
            }
        }
    }
}
  • Related