OSX
Swift

【OSX】Viewにブラーをかける

More than 3 years have passed since last update.

advent_calender_8.png

この記事は Goodpatch Advent Calendar 2015 8日目の記事です。昨日は

@subuta_nicoWallaby.jsを活用したテスト駆動開発についてでした!


こんにちは@hanamijuです。GoodpatchでOSXアプリを開発しています。

OSX Yosemiteからツールバーやサイドメニューなどに、擦りガラスのようなブラー効果をかけれるようになりました。こちらのやり方についてご紹介します。


とりあえずブラーをかける

ブラーのかかったViewを表示するためにYosemite以降では特別がんばる必要はありません。

実際に表示するためにはNSViewをいじるのではなく、NSVisualEffectViewというNSViewのサブクラスを使用します。


やり方

Interface BuilderのViewのクラス名をいじるだけです。

スクリーンショット 2015-12-05 17.03.15.png


結果

スクリーンショット 2015-12-05 15.25.37(2).png

超簡単ですね。

ちなみに、Inteface BuilderにもNSVisualEffectViewがあります。

スクリーンショット 2015-12-05 15.24.20.png

ここからViewに設定してもブラーのかかったViewを表示することができます。


ブラーをかける対象について(In behind-window or With in-window)

NSVisualEffectViewがブラーをかける対象は以下の二つがあります。


  • In behind-window (ブラーがかかっているViewの背景にブラーをかける)

  • With in-window (ブラーがかかっている同一ウィンドウ内でブラーをかける)


In behind-window

こちらのわかりやすい例はFinderのサイドメニューです。ウィンドウの外側(の壁紙)に対してブラーがかかっています。背景が透けているのでウィンドウレベルでの階層の視覚化ができます。

finder_sidebar_2x.png


With in-window

こちらのわかりやすい例としてはMapsの経路表示です。ウィンドウ内の階層を意識させたい時に使えます。

↓では経路表示のViewのブラーはその下のMapに対してかかっていることがわかります。

overlay_defers_2x.png


やり方

NSVisualEffectViewのblendingModeを変更するだけです。

blendingModeWithinWindowにする場合はview.wantsLayer = trueにする必要があります。

effectView.wantsLayer = true             // これないと実行時に落ちる。

effectView.blendingMode = .WithinWindow


ブラーの上でベタ塗りのViewを重ねたい

NSVisualEffectViewにControlを乗せるといい感じに色がブレンディングされます。

いちいちControlの設定変更を行わないで済むので楽なのですが、ブラーの上にブラーのかかっていないViewを重ねたい場面もあると思います。簡単にできそうなのですがちょっとつまづいたのでやり方を残します。


サンプル

以下のように、ブラーの上にベタ塗りのViewを貼り付けるサンプルを作ります。

スクリーンショット 2015-12-06 13.40.21.png


StoryBoardをいじる

View → VisualEffectView → ベタ塗りしたいView(今回はHogeView1) → その上のコントロール っていう階層でコンポーネントを配置します。

スクリーンショット 2015-12-06 13.45.30.png

余談ですが、VisualEffectViewのAppearanceはデフォルトでDarkに設定されているのでInterfaceBuilder上で設定を変えるにはView - Appearanceの設定をVibrant Lightに設定します。

(VisualEffectViewの項目になかったので一瞬えっ!ってなりました...)


この状態でビルドしてみた

スクリーンショット 2015-12-06 16.36.59.png

このように、HogeViewがブラーに同化されてしまいました。

以下で、背景色を設定していきます。


コーディング

普通に実装するとdrawRect()NSColor.whiteColor().set()的なことをする2のですが、これだと上図と同じくHogeViewにブラーがかかったままになります。

それじゃどうするのかというとCALayerレベルで設定します。

まずHogeViewをOutletに設定してwantsLayer = trueします。

その後HogeViewのlayer.backgroundColorで背景色の設定をします。


ViewController.swift

import Cocoa

class ViewController: NSViewController {

@IBOutlet weak var hogeView: HogeView!
override func viewDidLoad() {
super.viewDidLoad()

hogeView.wantsLayer = true
}
}

class HogeView: NSView {

override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
//NSColor.whiteColor().set() <- コレ呼んでも背景ベタ塗りされないよ
}

override func layout() {
super.layout()
self.layer?.backgroundColor = NSColor.whiteColor().CGColor // 背景色
// お好みでどうぞ
self.layer?.borderColor = NSColor.grayColor().CGColor // ボーダー色
self.layer?.borderWidth = 2 // ボーダーの太さ
self.layer?.cornerRadius = 8 // 角丸の半径
}
}



結果

できて............ない!

スクリーンショット 2015-12-06 14.19.56.png

Labelの背景にブラーがかかっています。

これを直すにはLabelの背景色を透明にする必要があります。

InterfaceBuilder上でDisplay - Draws Backgroundにチェックを入れた状態でBackgroundのAlphaを0に設定します。

スクリーンショット 2015-12-06 14.22.06.png

ちょっとイマイチな感じですが、これで最初の画像のように上手く表示することができます。


TableViewにブラーをかけたい

TableView(OutlineView)にブラーをかける時はNSVisualEffectViewを使用するのではなく、TableView自体にブラー設定するプロパティが存在するのでそれを使います。


やり方

InterfaceBuilderから対象のTableViewを選択して、TableView - Highlightの項目をSource Listにするだけです。

スクリーンショット 2015-12-06 12.59.56.png


Cellの選択状態の背景色をブラーに設定したい

私が調べた限りではFinderのサイドバーのように、TableViewにあるCellが選択状態の時の背景をブラーに設定する方法は見つかりませんでした。(知っている方いたら教えて欲しいです。)

スクリーンショット 2015-12-06 17.02.16.png

ですが、それっぽく見せる方法は存在します。


やり方

TableViewのサブクラスを作り、FirstResponderを受け付けなくすると選択した時に濃いブラーがかかった状態になります3

以下のコードをTableViewのサブクラスに記述します。


MyTableView.swift

override var acceptsFirstResponder: Bool { return false }


参考:How to get the source lists selection highlight to use the Dark Vibrancy appearance in OS X 10.10?


おわりに

以上、NSViewのブラーまわりの話でした。

公式ドキュメント以外あんまり情報が転がってないのでちょっと調べるのが手間でしたが分かれば簡単です。

明日はGoodpatchのProject Managerの@Hasedaから、エディタ初心者がSublimeTextでHTML5/CSS3を書く環境を作るのに苦労した話をお届けします。お楽しみに!





  1. HogeViewはNSViewのサブクラスです。 



  2. NSViewにはUIViewみたいなBackgroundColor的な親切プロパティは存在しません。(InterfaceBuilderからも色の設定はできない。) 



  3. FirstResponderを受け付けなくするとセルにフォーカスが当たらなくなるので作るアプリによっては注意が必要です。