Xcode Plug-in: NavigationBarShrinker

最近完成了一个Xcode插件,用来控制编辑器上方导航栏的显示。开发中学到了不少东西,小记一笔。

契机归功于Xcode 6 Beta3,把导航栏改宽了不少,导致垂直可视区域少了一行代码,Yosemite把标题栏缩短的优势也荡然无存。

开始做的时候只是想把导航栏的高度缩小就行了,后来突然想如果能直接控制让其缩小/恢复/直接消失岂不是更好用,顺带还可以学习操作NSView。
于是又加上了菜单和一些状态变换逻辑,才变成了下图的效果。

Xcode和AutoLayout

我是OS X/iOS新手,但是在学习iOS开发时知道现在都用AutoLayout了,可以更好的适配屏幕。
于是我以为Xcode应该也在用Constraints来布局view。但测试后发现不是这样的,Xcode还是用的Autoresizing mask。这倒是让我略感惊讶,不过不用调整Constraints倒是省了不少事。

view的初始化时机

一开始的尝试是在viewWillMoveToWindow:里修改NavBar高度的,但是发现只改NavBar的话,会在NavBar上面出现一个灰色的条,editor并没有随着NavBar的缩短而跟着上去。要想让editor的高度跟着变,需要在调整NavBar的同时修改NavBar的superview的高度,使superview的高度和调整后的NavBar的高度一致才行。
这让我有点百思不得其解,因为目测NavBar的superview和editor的superview应该是一个(事实证明确实是这样,虽然不是严格意义上的superview相等,但包含NavBar的view确实同时包含Editor),如果把superview的高度改成和调整后的NavBar高度一致,那Editor不就看不到了?
试着打log看view的体系结构,也没看到Editor的踪影。这之后又尝试了许多歪门邪道,包括重新创建Constraints。都没法得到想要的结果。

直到后来把修改高度从NavBar的viewWillMoveToWindow:移到包含NavBar的ViewController(IDEEditorContext)里后,才明白原来和view的初始化顺序有关。
NavBar的viewWillMoveToWindow:被调用时,Editor还没被加载到view结构里,所以不管怎么打log也看不到editor,而这时候强行把NavBar连同其superview一起改到目标高度也是没有问题的,后面Editor加载进来后就会把superview再撑开。

所以最后的做法是在包含NavBar的ViewController里,在所有view都加载完的时刻(IDEEditorContext里有个viewDidInstall),获取到NavBar和Editor的高度,然后对二者同时进行高度调整。

NSView的坐标系

在缩小NavBar时,我直接调整的frame,但是发现要把NavBar往上挪,需要把y坐标加上某个值而不是减去。后来查资料才知道原来NSView的坐标系原点和iOS的左上角不同,是在左下角的,这确实够分裂的。

NSNotificationCenter

在用通知中心时了解到postNotificationName:object:方法是同步的,如果要异步,应该用NotificationQueue。