Skip to content

Commit

Permalink
Fixes the sticky footer not drawing in the bottom safe area. (#4422)
Browse files Browse the repository at this point in the history
  • Loading branch information
JayShortway authored Oct 30, 2024
1 parent 2ad11a5 commit 03b317f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
56 changes: 53 additions & 3 deletions RevenueCatUI/Templates/Components/Root/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import SwiftUI

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
struct RootView: View {
@State private var additionalFooterPaddingBottom: CGFloat = 0

private let viewModel: RootViewModel
private let onDismiss: () -> Void

Expand All @@ -31,13 +33,61 @@ struct RootView: View {
ScrollView {
StackComponentView(viewModel: viewModel.stackViewModel, onDismiss: onDismiss)
}.applyIfLet(viewModel.stickyFooterViewModel) { stackView, stickyFooterViewModel in
stackView.safeAreaInset(edge: .bottom) {
StackComponentView(viewModel: stickyFooterViewModel.stackViewModel, onDismiss: onDismiss)
}
stackView
.safeAreaInset(edge: .bottom) {
StackComponentView(
viewModel: stickyFooterViewModel.stackViewModel,
onDismiss: onDismiss,
additionalPadding: EdgeInsets(
top: 0,
leading: 0,
bottom: additionalFooterPaddingBottom,
trailing: 0
)
)
}
// First we ensure our footer draws in the bottom safe area. Then we add additional padding, so its
// background shows in that same bottom safe area.
.ignoresSafeArea(edges: .bottom)
.onBottomSafeAreaPaddingChange { bottomPadding in
self.additionalFooterPaddingBottom = bottomPadding
}

}
}

}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
private struct OnBottomSafeAreaPaddingChangeModifier: ViewModifier {
private let callback: (CGFloat) -> Void

init(_ callback: @escaping (CGFloat) -> Void) {
self.callback = callback
}

func body(content: Content) -> some View {
content
.background(
GeometryReader { geometry in
Color.clear
.onAppear {
callback(geometry.safeAreaInsets.bottom)
}
.onChange(of: geometry.safeAreaInsets.bottom) { newValue in
callback(newValue)
}
}
)
}
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
fileprivate extension View {
/// Sort-of backported safeAreaPadding (iOS 17+), for as much as we need.
func onBottomSafeAreaPaddingChange(_ callback: @escaping (CGFloat) -> Void) -> some View {
self.modifier(OnBottomSafeAreaPaddingChangeModifier(callback))
}
}

#endif
10 changes: 10 additions & 0 deletions RevenueCatUI/Templates/Components/Stack/StackComponentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ struct StackComponentView: View {

let viewModel: StackComponentViewModel
let onDismiss: () -> Void
/// Used when this stack needs more padding than defined in the component, e.g. to avoid being drawn in the safe
/// area when displayed as a sticky footer.
let additionalPadding: EdgeInsets

init(viewModel: StackComponentViewModel, onDismiss: @escaping () -> Void, additionalPadding: EdgeInsets? = nil) {
self.viewModel = viewModel
self.onDismiss = onDismiss
self.additionalPadding = additionalPadding ?? EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
}

var body: some View {
Group {
Expand All @@ -42,6 +51,7 @@ struct StackComponentView: View {
}
}
.padding(viewModel.padding)
.padding(additionalPadding)
.width(viewModel.width)
.background(viewModel.backgroundColor)
.cornerBorder(border: viewModel.border,
Expand Down

0 comments on commit 03b317f

Please sign in to comment.