Skip to content

Instantly share code, notes, and snippets.

@buscarini
Created February 21, 2022 07:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buscarini/122516641cd0ee275dd367786ff2a736 to your computer and use it in GitHub Desktop.
Save buscarini/122516641cd0ee275dd367786ff2a736 to your computer and use it in GitHub Desktop.
A SwiftUI view that centers the content in the screen if it fits
import Foundation
import SwiftUI
public protocol CGSizePreferenceKey: PreferenceKey where Value == CGSize {}
public extension CGSizePreferenceKey {
static func reduce(value _: inout CGSize, nextValue: () -> CGSize) {
_ = nextValue()
}
}
public extension View {
func onSizeChanged<Key: CGSizePreferenceKey>(
_ key: Key.Type,
perform action: @escaping (CGSize) -> Void
) -> some View {
self.background(
GeometryReader { geo in
Color.clear
.preference(key: Key.self, value: geo.size)
}
)
.onPreferenceChange(key) { value in
action(value)
}
}
}
struct ChildViewSize: CGSizePreferenceKey {
static var defaultValue: CGSize = .zero
}
public struct GlobalHCenteringView<Content: View>: View {
@State private var childSize: CGSize = .zero
private let content: () -> Content
public init(
content: @escaping () -> Content
) {
self.content = content
}
func offsetX(
frame: CGRect,
parentWidth: CGFloat
) -> CGFloat {
let parentCenter = parentWidth / 2
let childWidth = ceil(childSize.width)
let childHalf = childWidth / 2
let childPosition = parentCenter - childHalf - frame.origin.x
let minX = childPosition
let maxX = childPosition + childWidth
let centerInFrame = (frame.width - childWidth) / 2
return minX < 0
? centerInFrame
: maxX > frame.width
? centerInFrame
: childPosition
}
public var body: some View {
GeometryReader { geometry in
content()
.onSizeChanged(ChildViewSize.self) { size in
self.childSize = size
}
.frame(height: geometry.frame(in: .global).height)
.offset(
x: self.offsetX(
frame: geometry.frame(in: .global),
parentWidth: UIScreen.main.bounds.width
),
y: 0
)
}
.frame(height: childSize.height)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment