この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
Xamarin.Macを使用すると、C#でネイティブなMacのアプリが作成可能です。 ここでは、私自身がXamarin.Macに入門して学習した事項を覚書として書かせて頂いています。
今回は、コレクションビューを使用してみました。
コレクションビューは、テーブルビューやアウトラインビューと違って、個々のアイテムを表示するための組み込みビューがありません。 これを独自に用意する必要がある事から、やや、ハードルの高いものとなっているかも知れません。
2 CollectionViewの配置
Interface Builderで、メインとなるビューにCollection Viewを配置し、ウインドウいっぱいに表示されるように制約を追加します。
また、AssistantエディタでViewController.hを開いてOutletを接続します。 ( 接続するコントロールがNSCollectionViewになっていることに注意が必要です。)
3 ビューの作成
ファイル > 新しいファイル > Mac > View Controllerと辿り、新規にビューを作成します。(ここでは、名前をMyItemとしました)
この時、以下の3つのファイルが生成されます。
- MyItem.cs
- MyItem.xib
- MyItemController.cs
操作の対象を、MyItemController.csとしたいのですが、これをプロトタイプとしてビューコントローラーを登録するとき、xibと名前が一致している必要があるため、MyItem.xibをMyItemController.xibに変更します。
続いて、CollectionViewItem.xibをInterface Builderで開いて、Boxを配置し、ビューいっぱいに表示されるように制約を追加します。Boxは、デフォルトでタイトル(Box)が表示される状態になっているので、とりあえずそのままにしておきます。
MyItemControllerクラスは、NSCollectionViewItemを継承するように書き換えます。
MyItemController.cs
public partial class MyItemController : NSCollectionViewItem {
#region Constructors
// Called when created from unmanaged code
public MyItemController(IntPtr handle) : base(handle) {
Initialize();
}
4 DataSource/Delegate
コレクションビューのデリゲートクラスとしてNSCollectionViewDelegateFlowLayoutを継承した、CollectionViewDelegateクラスを作成します。
NSCollectionViewDelegateFlowLayoutは、組み込みのレイアウト型です。
using AppKit;
namespace Sample001 {
public class CollectionViewDelegate : NSCollectionViewDelegateFlowLayout {
public CollectionViewDelegate() {
}
}
}
データクラスは、NSCollectionViewDataSourceを継承して作成します。
GetNumberofItems()は、データ数を返すメソッドですが、ここでは、仮に10個アイテムがあるという想定で、10を返しておきます。
GetItem()は、ここのアイテム(NSCollectionViewItem)を返すメソッドなので、MyItemControllerクラスを生成して返しています。
namespace Sample001 {
public class CollectionViewDataSource: NSCollectionViewDataSource {
public CollectionViewDataSource() {
}
public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) {
var item = collectionView.MakeItem("cell", indexPath) as MyItemController;
return item;
}
public override nint GetNumberofItems(NSCollectionView collectionView, nint section) {
return 10;
}
}
}
5 初期化
最後に、ViewControllerのViewDidLoad()で、コレクションビューの初期化を行います。
NSCollectionViewFlowLayout() で、150✕150のレイアウトを定義して、コレクションビューに設定してます。(①)
個々のアイテムを表示するために準備した、MyItemControllerは、RegisterClassForItemでコレクションビューに登録しています。(②)
Delegate及び、DataSourceも、通常通り登録しています。(③、④)
public partial class ViewController : NSViewController {
public ViewController(IntPtr handle) : base(handle) {
}
public override void ViewDidLoad() {
base.ViewDidLoad();
// MyItemControllerの登録(②)
CollectionView.RegisterClassForItem(typeof(MyItemController), "cell");
// DataSource(③)
CollectionView.DataSource = new CollectionViewDataSource();
// Flow layout(①)
var flowLayout = new NSCollectionViewFlowLayout() {
ItemSize = new CGSize(150, 150),
SectionInset = new NSEdgeInsets(10, 10, 10, 20),
MinimumInteritemSpacing = 10,
MinimumLineSpacing = 10
};
CollectionView.WantsLayer = true;
CollectionView.CollectionViewLayout = flowLayout;
// Delegate(④)
CollectionView.Delegate = new CollectionViewDelegate();
}
ここまでの実装で、10個のアイテムが表示されていることを確認できます。
6 データ表示
元となるデータクラスは、下記で作成したものを使用します。
Product.cs
[Register("Product")]
public class Product : NSObject {
private string _name;
private int _price;
public Product(string name, int price) {
_name = name;
_price = price;
}
[Export("Name")]
public string Name {
get {
return _name;
}
set {
WillChangeValue("Name");
_name = value;
DidChangeValue("Name");
}
}
[Export("Price")]
public int Price {
get { return _price; }
set {
WillChangeValue("Name");
_price = value;
DidChangeValue("Name");
}
}
}
MyItemControllerで、データクラスをプロパティとして定義します。
MyItemController.cs
public partial class MyItemController : NSCollectionViewItem {
// 商品(Product)クラスを定義
private Product _product;
// 商品(Product)クラスを公開
[Export("Product")]
public Product Product {
get { return _product; }
set {
WillChangeValue("Product");
_product = value;
DidChangeValue("Product");
}
}
ビューにLabelを追加して、公開されたプロパティにバインディングします。
データソースで商品クラスの配列(Data)を定義し、GetItem() 及び、GetNumberofItems() で、それを返すように書き換えます。
CollectionViewDataSource.cs
public class CollectionViewDataSource: NSCollectionViewDataSource {
public List<Product> Data;
public CollectionViewDataSource() {
}
public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) {
var item = collectionView.MakeItem("cell", indexPath) as MyItemController;
item.Product = Data[(int)indexPath.Item];
return item;
}
public override nint GetNumberofItems(NSCollectionView collectionView, nint section) {
return Data.Count;
}
}
データソースのデータは、ViewControllerのViewDidLoadで生成します。
ViewController.cs
<br />public partial class ViewController : NSViewController {
public override void ViewDidLoad() {
base.ViewDidLoad();
// ・・・略・・・
// データ
var Products = new List<Product>();
Products.Add(new Product("AAA", 100));
Products.Add(new Product("BBB", 120));
Products.Add(new Product("CCC", 1300));
Products.Add(new Product("DDD", 220));
Products.Add(new Product("EEE", 950));
((CollectionViewDataSource)CollectionView.DataSource).Data = Products;
}
実行すると、定義した商品データの表示を確認できます。
7 最後に
今回は、コレクションビューを使用してみました。
アイテム用のビューの準備や、レイアウト定義など、色々作業が多くなっています。また、データバインディングも必須となることから、やはり、コレクションビューの利用は、ちょっと大変です。