NEW: Learn to build the incredible iOS 15 Weather app today! >>

How to implement window zoom?

Forums > SwiftUI

I would like to implement zoom behaviour using SwiftUI. Where should I call zoom(_:)?

Edit: Updated title

   

@Obelix, sorry, should have been more clearer. It's not about image zooming but rather window zooming for changing the window size in accordance with the window contents.

When pressing the green window button with option key held, the window size should increase/decrease.

   

That behavior is provided automatically. The programmer doesn't need to implement any methods. If I create a macOS project, I don't have to do anything and all three buttons just work out of the box. Where are you having an issue?

   

roosterboy, indeed you are right. I am playing with a basic application draft, and after removing some unnecessary constraints I was able to get a behaviour that did not maximise the window, but kept it within the set boundaries.

However, I could still use your advice. Right now, I am using a fixed value for my minimum root size, say 300-300, and it correctly switches between the minimum window size and the frame size for the child view. But if I remove all .frames, it gets back to maximising the window, without taking the child view size into account (let's say it's a Text and on paper it only takes the amount of space it needs.

My question is, what is the best practice to make the zoomed size always the size of the child view? I used GeometryReader on the child view (geo.size.width, geo.size.height) but to no avail. How to make the window resize to the minimum size of the Text view?

Sample code below:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            RootView()
                .background(Color(.windowBackgroundColor))
                .onReceive(NotificationCenter.default.publisher(
                    for: NSApplication.willUpdateNotification), perform: { _ in
                        for window in NSApplication.shared.windows {
                            window.collectionBehavior = .fullScreenAuxiliary
                        }
                })
        }
    }
}

struct RootView: View {    
    var body: some View {
        GeometryReader { geo in
            Text("Hello, world!")
                .frame(minWidth: geo.size.height, maxWidth: 500, minHeight: geo.size.height, maxHeight: 500)
                .toolbar {
                    ToolbarItemGroup(placement: .status) {
                        Spacer()
                        StatusView()
                        Spacer()
                    }
                }
        }
    }
}

Above code crashes, BTW. :D

   

I think I spoke too soon about getting rid of GeometryReader. Without it, a static view resizes fine, but I still couldn't find a solution to these two issues:

  • It's not possible to resize the view freely past the optimal size, and get back the optimal size when pressed zoom button
  • Adding a ScrollView makes Swift think it should have unlimited size on the direction of the scroll view.

I'll update if I find a solution.

   

I couldn't find a way to fix it. Can someone have a look at the code below:

@main
struct ZoomApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(minWidth: 50,
                       maxWidth: .infinity,
                       minHeight: 50,
                       maxHeight: .infinity)
        }
    }
}

struct ContentView: View {
    var body: some View {
        Text("This is an experimental piece of text.")
            .padding(50)
            .border(Color.red, width: 5)
            .fixedSize()
    }
}
  1. Window will have a minimum size, that won't allow resizing smaller than this point
  2. Window will have a zoom size, which will get the size of the Views, and return an optimal window size that only contains the bounds of these views
  3. Window will be free to resize to bigger dimensions, only to return to step two when zoom is triggered

Basically, the zoom behaviour should always return to below state:

Screenshot

I will appreciate any possible help. It looks like this should be the textbook zoom behaviour, but for some reason it does not work.

   

I figured out how to switch between sizes.

extension NSWindowController: NSWindowDelegate {
    public func windowWillUseStandardFrame(_ window: NSWindow, defaultFrame newFrame: NSRect) -> NSRect {
        return NSRect(origin: window.frame.origin, size: CGSize(width: 500, height: 500))
    }
}

I will now try to figure out how to pass SwiftUI constrains to this function.

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.