Unexpected Frame Resizing Behavior During Animation of safeAreaInset content.

Hey everyone! I’m encountering an issue while attempting to animate height changes of the content inside safeAreaInset(edge:alignment:spacing:content:).

When animating a reduction in the frame height, the container view (in my case, Map) also animates unexpectedly. However, when animating an increase in the frame height, the animation works smoothly, and the Map view remains still.

How can I address this odd resizing behavior of the container?

Code:

struct MapView: View {

    var body: some View {
        Map()
            .safeAreaInset(edge: .bottom) {
                MapDetailView()
            }
    }
}

struct MapDetailView: View {

    @State private var oldHeightOffset: CGFloat = 0
    @State private var newHeightOffset: CGFloat = 0
    @State private var containerHeight: CGFloat = 0

    private var drag: some Gesture {
        DragGesture(coordinateSpace: .global)
            .onChanged { value in
                withAnimation(.interactiveSpring) {
                    newHeightOffset = oldHeightOffset + value.translation.height
                }
            }
            .onEnded { value in
                switch newHeightOffset {
                case containerHeight * 0.625...containerHeight:
                    withAnimation(.spring) {
                        newHeightOffset = containerHeight * 0.75
                    }
                case containerHeight * 0.25..<containerHeight * 0.625:
                    withAnimation(.spring) {
                        newHeightOffset = containerHeight * 0.5
                    }
                case 0..<containerHeight * 0.25:
                    withAnimation(.spring) {
                        newHeightOffset = 0
                    }
                default:
                    break
                }
                oldHeightOffset = newHeightOffset
            }
    }

    var body: some View {
        NavigationStack {
            Rectangle()
                .fill(.clear)
                .containerBackground(.ultraThinMaterial, for: .navigation)
        }
        .gesture(drag)
        .containerRelativeFrame(.vertical) { length, _ in
            length - newHeightOffset
        }
        .onGeometryChange(for: CGFloat.self) { geometryProxy in
            let frame = geometryProxy.frame(in: .local)
            return frame.height + newHeightOffset
        } action: { containerHeight in
            self.containerHeight = containerHeight
        }
    }
}

Reducing safe area inset's content height (drag down):

Increasing safe area inset's content height (drag up):

Are you looking to implement a sheet presentation at the bottom of the screen? If that's your goal, a different way to do that is to use the sheet modifier and specify presentation detents.

— Ed Ford,  DTS Engineer

I'm having this same issue on a Map as well, but with safeAreaPadding instead of safeAreaInset.

When I increase the padding, the map adjusts gracefully. When I reduce the padding, the map flashes white between in the changed area.

@mattro provided something interesting in a comment:

However I have this issue occurring with a sheet & presentation detents as well.

When I increase the size of the sheet (to say, .medium), I have a function that sees the change of detent and updates safeAreaPadding. This works fine, and smooth. If I reduce the size of the sheet, perhaps by dismissing it, when the function sets the safeAreaPadding to 0, the map still flashes white in the changed area.

That removes the circumstances of a TabView from the picture and focuses on the issue with respect to the detents, insets, and padding. As such, I'd like you to file a bug report with a buildable test project demonstrating that. Once you've done that, please post the FB number here for the record.

— Ed Ford,  DTS Engineer

Unexpected Frame Resizing Behavior During Animation of safeAreaInset content.
 
 
Q