直入主題,本文來講一講關(guān)于Mac上最常用的控件之一NSSplitView的一些相關(guān)問題。
首先,NSSplitView作為分隔內(nèi)容的一個(gè)視圖,支持拖拽改變分隔區(qū)域的大小,支持塌陷(collaps)。但是NSSplitView在與autolayout混合使用的時(shí)候會(huì)有很多問題。
通常我們需要類似QQ的效果,我們需要的是當(dāng)我們拉伸整個(gè)視圖的時(shí)候,某一個(gè)子視圖會(huì)被拉伸,而其他的視圖保持原有大小,當(dāng)我們拉伸整個(gè)視圖的時(shí)候,我們同樣經(jīng)常需要壓縮某一個(gè)視圖而保持其他視圖的尺寸,當(dāng)被壓縮的子視圖達(dá)到我們?cè)O(shè)定的最小尺寸的時(shí)候,我們會(huì)尋找第二低HoldingPriority的視圖進(jìn)行壓縮,直到所有的視圖都達(dá)到我們?cè)O(shè)定的最小尺寸,或是整個(gè)窗口已經(jīng)達(dá)到最小尺寸為止。
問題一:
當(dāng)我們使用autolayout來控制splitView的每個(gè)子視圖的尺寸的時(shí)候,我們會(huì)發(fā)現(xiàn)一個(gè)現(xiàn)象如圖:
鼠標(biāo)位置明明已經(jīng)達(dá)到autolayout最大約束了,但是還是顯示向右可拖拽的單向箭頭。控制箭頭的類型要通過實(shí)現(xiàn)NSSplitViewDelegate下的
optional func splitView(splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat
optional func splitView(splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat
來實(shí)現(xiàn)。但是,當(dāng)我們?cè)贜SSplitViewController直接Override以上兩個(gè)方法的話,會(huì)直接crash,所以我采用的方法是生命一個(gè)代理對(duì)象,然后把代理對(duì)象設(shè)置成splitView的delegate,這樣在override上邊兩個(gè)方法就可以正常執(zhí)行了,但是,鼠標(biāo)類型是對(duì)了,又產(chǎn)生了其他問題。
問題二:
本來,我是使用autolayout來控制各個(gè)子視圖的尺寸的,但是使用autolayout約束字視圖大小時(shí)如果和代理方法設(shè)置的constrainMaxCoordinate、constrainMinCoordinate沖突的話會(huì)報(bào)錯(cuò),所以保險(xiǎn)起見,我們最好移除所有和這兩個(gè)屬性相關(guān)的約束。我本來以為,這樣的話我的問題就解決了。但是,too young too simple。
問題三:
optional func splitView(splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat
optional func splitView(splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat
optional func splitView(splitView: NSSplitView, resizeSubviewsWithOldSize oldSize: NSSize)
func splitView(splitView: NSSplitView, shouldAdjustSizeOfSubview view: NSView) -> Bool
如果設(shè)置了NSSplitView實(shí)例對(duì)象的delegate,并且實(shí)現(xiàn)了以上四個(gè)代理方法中某一個(gè),則splitView的每個(gè)subview的HoldingPriority會(huì)失效,也就是在拉伸或者壓縮整個(gè)splitview的時(shí)候HoldingPriority比較低的subview不會(huì)被優(yōu)先拉伸,而是以默認(rèn)情況下按照所占比例整體拉伸相應(yīng)的距離,這個(gè)反饋太shit了。在沒有其他辦法的情況下,我們不得不硬著頭皮實(shí)現(xiàn)上邊四個(gè)方法中的倒數(shù)第二個(gè),來純手動(dòng)計(jì)算不同情況下各個(gè)子視圖的大小,這個(gè)地方寫起來是非常麻煩的。下邊提供一個(gè)范例:
func splitView(splitView: NSSplitView, resizeSubviewsWithOldSize oldSize: NSSize) { // 字視圖通常分為兩個(gè)部分,內(nèi)容子視圖和分割線視圖(分割線視圖也是有尺寸的,所以要計(jì)算在內(nèi)) let dividerThickness = splitView.dividerThickness // 如果當(dāng)前的splitView的寬度和之前的寬度沒有變化,證明我們沒有拉伸或者壓縮splitView,這樣我們就可以調(diào)用adjustSubviews()讓系統(tǒng)自己設(shè)置divider的位置,我們就不用操心這種情況下的子視圖的大小和位置了,但是,如果對(duì)splitView進(jìn)行了拉伸或者壓縮,這個(gè)時(shí)候我們?cè)趯?shí)現(xiàn)了某個(gè)代理方法之后就不得不自己去計(jì)算各種情況下每個(gè)視圖的位置和大小。 if (splitView.frame.size.width == oldSize.width) { splitView.adjustSubviews() return } //以下的代碼只是用來說明需要自己計(jì)算位置和大小,并沒有任何實(shí)質(zhì)意義,可以不必仔細(xì)閱讀 for var index = 0; index < splitView.subviews.count; index++ { let subview = splitView.subviews[index] as! NSView subview.frame = NSMakeRect((splitView.frame.size.width - dividerThickness) / CGFloat(splitView.subviews.count) * CGFloat(index) + CGFloat(index) * dividerThickness, 0, (splitView.frame.size.width - dividerThickness) / CGFloat(splitView.subviews.count), splitView.frame.size.height) } }
另,NSSplitViewController是OS X 10.10中新加入的api,用起來是非常方便的,但是如果需要考慮向下兼容的話還是不要用了。
以上是筆者遇到的一些問題,如果有地方表達(dá)不是很清楚的話歡迎與我交流。QQ:2680914103 轉(zhuǎn)載請(qǐng)注明出處,感謝支持