NSTableCellView のサイズを自動的に調整させてみる

Cocoa プログラミング

NSTableCellView のサイズを表示するテーブルビューや扱うコンテンツによって自動的に調整されるようにしてみました。


View ベースの NSTableView で、各行の NSTableCellView が扱うコンテンツに応じてサイズ(高さ)を自動調整する方法を考えてみました。

行ごとに高さを指定する

NSTableView で行の高さを指定するには、NSTableViewDelegate に定義されている次のメソッドを使用します。

optional public func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat

このメソッドには、対象となる行が 変数row で渡ってくるので、その行で扱うコンテンツを想定して適切な行の高さを返せば良いことになるのですけど、実際の高さをどう計算したらいいかが難しいところです。

今回は実際の View を作って計算してみる

扱うコンテンツが決まっていたり、レイアウトが確実に固定されている幾つかの種類の View を扱うだけなら簡単なのですけど、例えばインターネットから情報を取得して表示するような場合には、表示する View の高さが変動するため、実際にやってみないとわからないところもあったりします。

それなら、今回は実際に View を作ってコンテンツを設定してみて、それを表示するのに必要な View の高さを計算する方法を採ってみようと思います。


この方法の最大の欠点は、高さを推定するときと実際に表示するときの両方で View を作らないといけないところです。

例えばリソースファイルからの画像読み込みなどの View を準備する時に時間がかかる処理がある場合には、高さを計算する時にはせめて設定しないようにしたりするなどの工夫をすると良いかもしれません。

View の高さを固定しないようにする

今回は NSTextField に設定したテキストの量に応じて高さが変わるようにしたいと思うので、目的のラベルには高さを指定せず、親ビューとの余白だけを指定しました。

設定されているテキストに応じて NSTextField の高さは自動で調整される性質があるため、これでテキストの量に応じて親の View のサイズを調整できるはずです。

実際のところは、テキストを設定してもすぐには frame にサイズが反映されなくて、View の fittingSize を呼び出すことで、テキストの量に応じたサイズを取得できる様子でした。

行の表示に必要な高さを返す

ここまで出来たら実際に、行の表示に必要な高さを返すコードを作ります。

行を表示したい頃合いになると NSTableViewNSTableViewDelegatetableView:heightOfRow:メソッド を呼び出します。

ここで次のようにして、行の表示で使う View を作成して値を設定し、それを表示するのに必要な View の高さを取得しています。

extension TimelineViewController : NSTableViewDelegate {

	func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
		
		let view = tableView.makeViewWithIdentifier("TimelineCell", owner: self) as! TimelineTableCellView
			
		view.status = self.tweets[row]
		
		return view.fittingSize.height
	}
}

このようにすることで、View の適切な高さを tableView:heightOfRow:メソッド が返してくれるようになって、期待通りの高さで View が表示されるようになりました。