iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
macOSとiOSのUI関連のフレームワークには差異があり、前者はNeXTSTEPから受け継がれたスタイルとなっていて、後者は貧弱な計算機リソースでの利用を想定した設定となっている。
ただ、最近ではmacOSのフレームワークの方がiOSの方に合わせることが可能な部分については似せてきていて、テーブルビューの場合は昔からのCell BasedとiOSと同様なView Basedの二通りの方式があるという状況だ。前者については非推奨となっているため、後者についてサンプルを作りながら説明する。
新規プロジェクトを生成。macOSでCocoa Appを選択。
"Use Storyboards"と"Create Document-Bassed Application"を選択する。
nib(ファイル名のsuffixはxib)でなくStoryboardを選んだ場合、iOSに似たViewControllerを利用した構成となる。iOS向けの開発経験者にとっては、その方が分かりやすいと思うが、macOSプログラミングの書籍の多くはnibの場合の説明となっているので、どちらが学習しやすいか悩ましい問題だ。ただ、今後はStoryboardだと思うので茨の道だがこちらの道を選択することにした。
Storyboardで、ViewにライブラリからTable Viewを配置し、TableViewのContent ModeがView Basedになっていることを確認する。
サンプルでは、テーブルの列を2にしたが、列に識別子をつけるのは大事だ。iOSの場合、列は1個のみなので、行番号となるインデックスのみで良かったが、macOSでは列を識別するものが必要だ。また、列の順番を変更することができるので、列インデックスでは対応できない。
Storyboardを選ぶと、ビューコントローラが生成されるが、これとTable ViewをdataSourceとdelegateで繋げる。
ターブルビューの行数や、表示する欄の設定は、iOSのUITableViewと似ている。
ViewControllerの親にNSTableViewDataSourceとNSTableViewDelegateを追加する。
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
...
}
行数を返す。
public func numberOfRows(in tableView: NSTableView) -> Int {
return 64
}
欄の内容をビューで返す。
public func tableView(_ tableView: NSTableView, viewFor
tableColumn: NSTableColumn?, row: Int) -> NSView? {
print(#function + " column:" +
tableColumn!.identifier.rawValue + " row:" + String(row))
var result: NSTextField? =
tableView.makeView(withIdentifier:NSUserInterfaceItemIdentifier(rawValue:
"MyView"), owner: self) as? NSTextField
if result == nil {
result = NSTextField(frame: NSZeroRect)
result?.identifier =
NSUserInterfaceItemIdentifier(rawValue: "MyView")
}
if let view = result {
print("view:" + view.identifier!.rawValue + " row:" + String(row))
if let column = tableColumn {
if column.identifier.rawValue == "TableColumn1" {
view.stringValue = "column 01"
}
else if column.identifier.rawValue == "TableColumn2" {
view.stringValue = "column 02"
}
}
}
return result
}
Storyboardで設定した識別子で列がわかるので、列に対応したビューを返している。
好奇心公正な人なら、非推奨だと分かっていても、以前のCell Basedが気になっていると思うので調べてみた。
行数を返すのは同様だ。
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
NSInteger count=0;
if (self.namesArray)
count=[self.namesArray count];
return count;
}
欄の内容を返すのも似ている。
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
id returnValue=nil;
NSString *columnIdentifer = [aTableColumn identifier];
NSString *theName = [namesArray objectAtIndex:rowIndex];
if ([columnIdentifer isEqualToString:@"name"]) {
returnValue = theName;
}
return returnValue;
}
ただ、メソッドの戻り値の型がidだ。どういう事なのだろうか?
Cell Basedでは、ビューを管理するセルが存在する。デフォルトでは文字列を表示するビューが用意され、それを管理するセルに対して、値となるNSStringを返しているということのようだ。
複雑な欄を表示したい場合、それ様のセルを用意することになるが、それが一手間となるし、セルはビューでないので、ビューの重なりも独自に保持しないといけない。
大変そうなので、Cell Basedの探求はここまでにしておこう。