I want to create a solution that tells me when the user has finished resizing a view. Currently, I’m using a timer for this, but I’m not satisfied with my approach because it doesn’t feel like idiomatic SwiftUI coding. I’m looking for a more native way to detect the final size of the view at the end of resizing. As we change the window size our view size would change.
import SwiftUI
struct ContentView: View {
@State private var resizeTimer: Timer? = nil
var body: some View {
GeometryReader { geometryValue in
Color.white
.onChange(of: geometryValue.size) { newValue in
// Invalidate any existing timer
resizeTimer?.invalidate()
// Start a new timer to detect when resizing ends
resizeTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { _ in // [weak self]
didEndResizing(size: newValue)
}
}
}
.padding()
}
private func didEndResizing(size: CGSize) {
print("View resizing ended. Final size: \(size)")
}
}
To detect the end of a window resizing session, you can observe the NSWindow.didEndLiveResizeNotification
.
.onReceive(NotificationCenter.default.publisher(for: NSWindow.didEndLiveResizeNotification)) { notification in
print("Resize did end!")
}
notification.object
tells you which NSWindow
it is that got resized, so if your app has multiple windows, you can check that to respond only to resizes of the view's own window. For example:
struct ContentView: View {
@State private var myWindow: NSWindow?
var body: some View {
Color.blue
.background { WindowAccessor(window: $myWindow) }
.onReceive(NotificationCenter.default.publisher(for: NSWindow.didEndLiveResizeNotification)) { notification in
if (notification.object as? NSWindow) == myWindow {
print("Did resize!")
}
}
}
}
struct WindowAccessor: NSViewRepresentable {
@Binding var window: NSWindow?
class MoveToWindowDetector: NSView {
var onMoveToWindow: (NSWindow?) -> Void = { _ in }
override func viewDidMoveToWindow() {
onMoveToWindow(window)
}
}
func makeNSView(context: Context) -> MoveToWindowDetector {
MoveToWindowDetector()
}
func updateNSView(_ nsView: MoveToWindowDetector, context: Context) {
nsView.onMoveToWindow = { window = $0 }
}
}
WindowAccessor
is slightly modified from Asperi's answer here.