Skip to content

Instantly share code, notes, and snippets.

@Priva28
Created February 22, 2024 10:12
Show Gist options
  • Save Priva28/53abcdef7de6633d776cb169c96ce014 to your computer and use it in GitHub Desktop.
Save Priva28/53abcdef7de6633d776cb169c96ce014 to your computer and use it in GitHub Desktop.
A window in visionOS with a changeable aspect ratio.
import SwiftUI
public struct UniformWindowGroup<Content: View>: Scene {
var id: String?
var maxWidth: CGFloat
var maxHeight: CGFloat
var aspectRatio: CGFloat
var content: Content
@State private var setSize: CGSize?
public init(id: String? = nil, maxWidth: CGFloat = 3000, maxHeight: CGFloat = 1500, aspectRatio: CGFloat, _ content: () -> Content) {
self.id = id
self.maxWidth = maxWidth
self.maxHeight = maxHeight
self.aspectRatio = aspectRatio
self.content = content()
}
public var body: some Scene {
if let id {
return WindowGroup(id: id) {
contentView
}
.windowResizability(.contentSize)
} else {
return WindowGroup {
contentView
}
.windowResizability(.contentSize)
}
}
private var contentView: some View {
GeometryReader { geo in
content
.onChange(of: aspectRatio) { _, aspectRatio in
setWindowAspectRatio(aspectRatio: aspectRatio, originalSize: geo.size)
}
.onAppear {
setWindowAspectRatio(aspectRatio: aspectRatio, originalSize: geo.size)
}
}
.frame(width: setSize?.width, height: setSize?.height)
}
private func setWindowAspectRatio(aspectRatio: CGFloat, originalSize: CGSize) {
let originalAspectRatio = originalSize.width / originalSize.height
var newWidth: CGFloat
var newHeight: CGFloat
if aspectRatio > originalAspectRatio {
newWidth = originalSize.height * aspectRatio
newHeight = originalSize.height
if newWidth > maxWidth {
newWidth = maxWidth
newHeight = newWidth / aspectRatio
}
} else {
newHeight = originalSize.width / aspectRatio
newWidth = originalSize.width
if newHeight > maxHeight {
newHeight = maxHeight
newWidth = newHeight * aspectRatio
}
}
newWidth = min(newWidth, maxWidth)
newHeight = min(newHeight, maxHeight)
let newSize = CGSize(width: newWidth, height: newHeight)
setResizingRestrictions(.none)
withAnimation(nil) {
setSize = newSize
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
setResizingRestrictions(.uniform)
setSize = nil
}
}
private func setResizingRestrictions(_ restrictions: UIWindowScene.ResizingRestrictions) {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
return
}
windowScene.requestGeometryUpdate(.Vision(resizingRestrictions: restrictions))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment