在之前的博文中我们实现了类似Reminder的实现:《自定义Mac标题栏样式》
然而,使用以上方法实现自定义标题栏,会带来一个额外的副作用:双击Title bar无法再实现默认Window的Zoom效果,即无法自动缩放窗口到全屏效果。
发现这个问题后我测试了Mac自带的Reminder应用,发现同样具有这个问题,由此可见这也许是一个OS X的 Bug,或是一个人所未知的“feature”。Anyway, 为了解决这个问题,我使用了一个比较非主流的方式,记录如下。
一、总体思路
通过查看文档和Storyboard文件,作为First Responder的Window具有一个叫做performZoom
的方法,而通过触发这个方法,Window就会执行缩放操作。
如此一来,问题的解决方案可以归为:
- 响应双击事件
- 判定点击区域是否在title bar内
- 执行
performZoom
进行缩放
二、具体实现
1. 响应双击事件
通过覆写mouseDown(with event: NSEvent)
方法,检测鼠标点击事件,实现代码如下:
override func mouseDown(with event: NSEvent) {
if (event.clickCount > 1) {
//双击相关处理
}
else{
super.mouseDown(with: event)
}
}
2. 判定点击区域是否在title bar内
通过event
检测鼠标点击的位置,并进一步通过func convert(_ point: NSPoint, to view: NSView?) -> NSPoint
方法将点击点映射到目的View上,从而检测是否点击到了所需的View上。代码如下:
let location = self.view.convert(event.locationInWindow, to: statusBar)
if (location.x >= 0 && location.y >= 0) {//即点击点位于statusBar内部
//执行操作
}
3. 执行performZoom
进行缩放
self.view.window?.performZoom(nil)
完整代码如下:
override func mouseDown(with event: NSEvent) {
if (event.clickCount > 1) {
//双击相关处理
let location = self.view.convert(event.locationInWindow, to: statusBar)
if (location.x >= 0 && location.y >= 0) {//即点击点位于statusBar内部
self.view.window?.performZoom(nil)
}
}
else{
super.mouseDown(with: event)
}
}
三、相关思考
其实一开始使用这样的方法我是拒绝的,因为怎么看都有一种 钦定 黑魔法的感觉。然而在有了比较多的Mac开发经历之后,我对此已经见怪不怪了。相比iOS, Mac开发总是需要subclass更多,hack更多。
除此之外,对知名应用Omnifocus的观察也让我觉得,这很可能是一条可行的路线,通过观察Omnifocus的行为,我发现其相应双击Zoom的响应区域更大,他的整个Tool Bar 和 Title Bar都可以响应双击事件,而根据我的解决方案,只需要将双击判定区域扩大到整个Tool Bar,即可轻松实现这个效果。再对比官方Reminders完全无法Zoom的行为,依然觉得Apple还得多加努力啊。