How to ignore safe area for container and respect safe area for content in swift UI
Asked Answered
F

1

9

I'm trying to create a bottom sheet in swift ui that looks something like this

https://user-images.githubusercontent.com/33900517/172068237-4dd58374-b6e6-4340-a913-7085fb64b254.mp4

My issue is that I have an animated bottom sheet, but because it is ignoring the safe area, when I click into the textfield it does not expand with the keyboard.

How would I fix this so the view expands with the keyboard but the white at the bottom still goes beyond the safe area?

I.e. the containing view should ignore the safe area, and the content within should adhere to the safe area.

Here is the bottom sheet code snippet, full example can be found here https://gist.github.com/CTOverton/4fbfb8db2de31f3b5f5ef9ee88e8f744

   var body: some View {
    GeometryReader { geometry in
      VStack() {
        self.content
      }
      .padding(.vertical, 34)
      .padding(.horizontal, 16)
//      .frame(width: geometry.size.width, height: geometry.size.height * heightRatio, alignment: .top)
      .frame(width: geometry.size.width, height: self.maxHeight, alignment: .top)
      .background(Color(.white))
      .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
              }
      )
    }
    .edgesIgnoringSafeArea([.bottom, .horizontal])
    .shadow(color: Color(hue: 1.0, saturation: 0.0, brightness: 0.0, opacity: 0.08), radius: 12, y: -8)
  }

I've tried various configurations of .ignoreSafeArea() and .safeAreaInset() but I just can't seem to get it quite right.

Here are some pictures for reference as well

Bottom sheet closed Bottom sheet open Bottom sheet open and textfield is selected, keyboard is active

Ferrocene answered 7/6, 2022 at 3:13 Comment(0)
B
5

Actually instead of ignoring safe area for everything (that results in issue), we need it only in background, so the question is how to correctly construct background in this case.

Note: the .cornerRadius is also not appropriate here, because it clips content

demo

Here is a main part of a fix. Tested with Xcode 13.4 / iOS 15.5

.background(
    RoundedRectangle(cornerRadius: Constants.radius)  // corners !!
        .fill(.white)                                 // background !!
        .edgesIgnoringSafeArea([.bottom, .horizontal]) // << only here !!
)

Complete test module is here

Basham answered 7/6, 2022 at 5:46 Comment(2)
I had a similar case, I needed to ignore safe area for Rectangle in VStack, ignored only for Rectangle and it workedMitosis
It feels like this is a bug with .cornerRadius, why should adding a cornerRadius remove the portion of the view that extends past the safe area? ESPECIALLY in situations where we only want to add a corner radius on top left and bottom right, we still find it affecting the bottom part of the view. very strange.Subvert

© 2022 - 2024 — McMap. All rights reserved.