Created
February 22, 2024 10:12
-
-
Save Priva28/53abcdef7de6633d776cb169c96ce014 to your computer and use it in GitHub Desktop.
A window in visionOS with a changeable aspect ratio.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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