基于 SwiftUI 视图转换的 NSWindow 动画

问题描述 投票:0回答:1

我有一个带有自定义圆形的 MacOS 菜单栏应用程序

NSWindow
:

class RoundedWindow: NSWindow {
    override var contentView: NSView? {
        didSet {
            guard let contentView = contentView else { return }
            contentView.wantsLayer = true
            contentView.layer?.cornerRadius = 10
            contentView.layer?.masksToBounds = true
        }
    }
}

class ClearBackgroundHostingController<Content>: NSHostingController<Content> where Content: View {
    override func loadView() {
        self.view = NSView()
        self.view.wantsLayer = true
        self.view.layer?.backgroundColor = NSColor.clear.cgColor
    }
}

还有我的

AppDelegate
中调整窗口大小的功能

func adjustWindowSize(to size: CGSize) {
        guard let window = windowController.window else { return }
        var newFrame = window.frame
        newFrame.size = size

        // Calculate the new Y position to keep the window top aligned.
        let newY = window.frame.maxY - size.height
        newFrame.origin.y = newY

        NSAnimationContext.runAnimationGroup({ context in
            context.duration = 10.0
            context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            window.animator().setFrame(newFrame, display: true)
        }, completionHandler: nil)
    }

我正在跟踪首选项窗口是否打开,并尝试相应地更新尺寸过渡并设置动画:

static let largeSize = CGSize(width: 512, height: 288)
static let smallSize = CGSize(width: 220, height: 220)
@State var size: CGSize = Self.smallSize

var body: some View {
    ZStack {
        if appDelegate.showingPreferences {
            PreferencesView(appDelegate: appDelegate)
        } else {
            if viewModel.isVPNAvailable || !viewModel.isVPNAvailable {
                mainContentView
            }
            
            if !viewModel.isVPNAvailable {
                vpnNotAvailableView
            }
        }
    }
    .onChange(of: appDelegate.showingPreferences) { _ in
        withAnimation(.easeInOut(duration: 1)) {
            let newSize = size == Self.largeSize ? Self.smallSize : Self.largeSize
            size = newSize
            appDelegate.adjustWindowSize(to: newSize)
        }
    }

    .onReceive(appDelegate.vpnStatusPublisher.receive(on: DispatchQueue.main)) { newStatus in
        actionInProgress = false
        switch newStatus {
        case .connected:
            appDelegate.vpnIsConnected = true
        case .connecting, .disconnecting, .disconnected:
            appDelegate.vpnIsConnected = false
        }
    }
    .onChange(of: appDelegate.showingPreferences) { _ in
        withAnimation(.easeInOut(duration: 1)) { // Adjust duration as needed
            size = size == Self.largeSize ? Self.smallSize : Self.largeSize
        }
    }
}

为了匹配这个CodePen动画:https://codepen.io/formfield/pen/zYeJzXz

但是,我似乎实际上无法让任何动画发生。我以正确的方式处理这个问题吗?

swift macos swiftui nswindow
1个回答
0
投票

我不知道您是否已经找到解决方案,但我认为错误在于您如何为框架设置动画。

窗框可以使用动画

window.setFrame(newFrame, display: true, animate: withAnimation)
https://developer.apple.com/documentation/appkit/nswindow/1419519-setframe

不幸的是,它的动画行为无法使用

NSAnimationContext.runAnimationGroup
进行调整。要调整持续时间,您可以使用:

© www.soinside.com 2019 - 2024. All rights reserved.