MacOSCatalyst:如何允许双击UIView来缩放窗口



默认情况下,在MacOS中,您可以双击窗口的标题栏进行缩放(调整大小以适应屏幕-不同于最大化(。再次双击它会将其恢复到以前的大小。

这在我的Catalyst应用程序上也很好。然而,我需要隐藏标题栏,并需要在标题栏区域中为我自己的自定义UIView提供双击行为。我可以用这个隐藏它:

#if os(OSX) || os(macOS) || targetEnvironment(macCatalyst)
UIApplication.shared.connectedScenes.forEach({
if let titlebar = ($0 as? UIWindowScene)?.titlebar {
titlebar.titleVisibility = .hidden
titlebar.toolbar = nil
}
})
#endif

有没有一种方法可以让我切换窗口缩放?

我可以使用一个变通方法来解决这个问题。UIKit/Catalyst本身没有提供任何方法来实现这一点。但我能够在上使用这篇文章中的第二种方法大纲

如何从Mac Catalyst应用程序访问AppKit API

https://betterprogramming.pub/how-to-access-the-appkit-api-from-mac-catalyst-apps-2184527020b5

我使用了第二种方法,而不是第一种方法,因为第一种方法似乎是私有的API(我可能错了(,将在应用商店中被拒绝。第二种方法是使用插件捆绑包并调用上面的方法,这对我来说很好。这样我不仅可以执行缩放,还可以执行其他MacOS Appkit功能,如监听键盘、鼠标滚动、悬停检测等。

创建插件捆绑包后,以下是我在插件中的代码:

Plugin.swift:

import Foundation
@objc(Plugin)
protocol Plugin: NSObjectProtocol {
init()
func toggleZoom()
func macOSStartupStuff()
}

MacPlugin.swift:

import AppKit
class MacPlugin: NSObject, Plugin {
required override init() {}
func macOSStartupStuff() {
NSApplication.shared.windows.forEach({
$0.titlebarAppearsTransparent = true
$0.titleVisibility = .hidden
$0.backgroundColor = .clear
($0.contentView?.superview?.allSubviews.first(where: { String(describing: type(of: $0)).hasSuffix("TitlebarDecorationView") }))?.alphaValue = 0
})
}
func toggleZoom(){
NSApplication.shared.windows.forEach({
$0.performZoom(nil)
})
}
}
extension NSView {
var allSubviews: [NSView] {
return subviews.flatMap { [$0] + $0.allSubviews }
}
}

然后我用我的iOS应用程序代码调用它。这在顶部添加了一个透明视图,双击会调用用于切换缩放的插件代码。

请注意,必须在viewDidPear或窗口初始化和显示后的某个位置调用此命令。否则它就不会起作用

#if os(OSX) || os(macOS) || targetEnvironment(macCatalyst)
@objc func zoomTapped(){
plugin?.toggleZoom()
}

var pluginWasLoaded = false
lazy var plugin : Plugin? = {
pluginWasLoaded = true
if let window = (UIApplication.shared.delegate as? AppDelegate)?.window {
let transparentTitleBarForDoubleClick = UIView(frame: .zero)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(zoomTapped))
tapGesture.numberOfTapsRequired = 2
transparentTitleBarForDoubleClick.addGestureRecognizer(tapGesture)
transparentTitleBarForDoubleClick.isUserInteractionEnabled = true

transparentTitleBarForDoubleClick.backgroundColor = .clear
transparentTitleBarForDoubleClick.translatesAutoresizingMaskIntoConstraints = false
window.addSubview(transparentTitleBarForDoubleClick)
window.bringSubviewToFront(transparentTitleBarForDoubleClick)

window.addConstraints([
NSLayoutConstraint(item: transparentTitleBarForDoubleClick, attribute: .leading, relatedBy: .equal, toItem: window, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: transparentTitleBarForDoubleClick, attribute: .top, relatedBy: .equal, toItem: window, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: transparentTitleBarForDoubleClick, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1, constant: 0),
transparentTitleBarForDoubleClick.bottomAnchor.constraint(equalTo: window.safeTopAnchor)
])
window.layoutIfNeeded()
}

guard let bundleURL = Bundle.main.builtInPlugInsURL?.appendingPathComponent("MacPlugin.bundle") else { return nil }
guard let bundle = Bundle(url: bundleURL) else { return nil }
guard let pluginClass = bundle.classNamed("MacPlugin.MacPlugin") as? Plugin.Type else { return nil }
return pluginClass.init()
}()
#endif

从视图调用DidPeare:

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
#if os(OSX) || os(macOS) || targetEnvironment(macCatalyst)
if !Singleton.shared.pluginWasLoaded {
Singleton.shared.plugin?.macOSStartupStuff()
}
#endif
}

最新更新