iOS Designer でのテーブルの操作
ストーリーボードは、iOS アプリケーションを作成するための WYSIWYG 手段であり、Mac と Windows 上の Visual Studio 内でサポートされています。 ストーリーボードの詳細については、「ストーリーボードの概要」ドキュメントを参照してください。 ストーリーボードを使用すると、テーブル内のセル レイアウトを編集することもできます。これにより、テーブルとセルを使用した開発が簡単になります。
iOS Designer でテーブル ビューのプロパティを構成する場合、選択できるセル コンテンツには、動的または静的プロトタイプ コンテンツの 2 種類があります。
動的プロトタイプ コンテンツ
プロトタイプ コンテンツを含む UITableView
は通常、データのリストを表示することを目的としています。この場合、1 つのプロトタイプ セル (または複数のセルを定義できるために複数のセル) がリスト内の各項目に再利用されます。 セルのインスタンスを作成する必要はありません。セルは、UITableViewSource
の DequeueReusableCell
メソッドを呼び出すことによって GetView
メソッドで取得されます。
静的コンテンツ
静的コンテンツを含む UITableView
を使用すると、テーブルをデザイン サーフェイス上で直接設計できます。 セルは、テーブルにドラッグし、プロパティを変更してコントロールを追加することでカスタマイズできます。
ストーリーボード駆動型アプリの作成
StoryboardTable の例には、ストーリーボードで両方の種類の UITableView を使用する単純なマスター詳細アプリが含まれています。 このセクションの残りの部分では、完成すると次のようになる小さな To Do リストの例を作成する方法について説明します。
ユーザー インターフェイスはストーリーボードを使用して構築され、両方の画面で UITableView が使用されます。 メイン画面ではプロトタイプ コンテンツを使用して行をレイアウトし、詳細画面では静的コンテンツを使用してカスタム セル レイアウトを使用してデータ入力フォームを作成します。
チュートリアル
Visual Studio で [(作成) 新しいプロジェクト…] > [単一ビュー アプリ (C#)] を使用して新しいソリューションを作成し、これに StoryboardTables という名前を付けます。
このソリューションでは、いくつかの C# ファイルを、既に作成されている Main.storyboard
ファイルと共に開きます。 Main.storyboard
ファイルをダブルクリックして iOS Designer で開きます。
ストーリーボードの変更
ストーリーボードは、次の 3 つの手順で編集します。
- 最初に、必要なビュー コントローラーをレイアウトし、プロパティを設定します。
- 2 番目に、オブジェクトをビューにドラッグ アンド ドロップして UI を作成します。
- 最後に、必要な UIKit クラスを各ビューに追加し、さまざまなコントロールに名前を付けてコードで参照できるようにします。
ストーリーボードが完了したら、コードを追加してすべてを動作させることができます。
ビュー コントローラーのレイアウト
ストーリーボードに対する最初の変更は、既存の Detail ビューを削除し、UITableViewController に置き換えることです。 次のステップを実行します。
ビュー コントローラーの下部にあるバーを選択して削除します。
ナビゲーション コントローラーとテーブル ビュー コントローラーをツールボックスからストーリーボードにドラッグします。
先ほど追加した 2 番目のテーブル ビュー コントローラーにルート ビュー コントローラーからセグエを作成します。 セグエを作成するには、Control キーを押しながら Detail セルから、新しく追加した UITableViewController にドラッグします。 [セグエの選択] で [表示] オプションを選択します。
作成した新しいセグエを選択し、このセグエをコードで参照するための識別子を付けます。 セグエをクリックし、次のようにプロパティ パッドに識別子の
TaskSegue
を入力します。
次に、2 つのテーブル ビューを選択し、プロパティ パッドを使用してこれらを構成します。 ビュー コントローラーではなくビューを選択するようにしてください。ドキュメント アウトラインを使用すると、選択の役に立ちます。
ルート ビュー コントローラーを [コンテンツ: 動的プロトタイプ] に変更します (デザイン サーフェイスのビューには、プロトタイプ コンテンツというラベルが付けられます)。
新しい UITableViewController を [コンテンツ: 静的セル] に変更します。
新しい UITableViewController には、クラス名と識別子が設定されている必要があります。 ビュー コントローラーを選択し、プロパティ パッドの [クラス] に「TaskDetailViewController」と入力します。これにより、ソリューション パッドに新しい
TaskDetailViewController.cs
ファイルが作成されます。 次の例に示すように、[ストーリーボード ID] として「detail」と入力します。 これは後で C# コードでこのビューを読み込むために使用されます。ストーリーボードのデザイン サーフェイスは次のようになります (ルート ビュー コントローラーのナビゲーション項目のタイトルが "Chore Board" に変更されました)。
UI を作成する
ビューとセグエが構成されたので、ユーザー インターフェイス要素を追加する必要があります。
ルート ビュー コントローラー
まず、マスター ビュー コントローラーでプロトタイプ セルを選択し、次に示すように [識別子] を「taskcell」として設定します。 これは後でコードで、この UITableViewCell のインスタンスを取得するために使用されます。
次に、次に示すように、新しいタスクを追加するボタンを作成する必要があります。
次の操作を行います。
- ツールボックスから [バー ボタン項目] をナビゲーション バーの右側にドラッグします。
- Properties Pad の [バー ボタン項目] の下で、[識別子: 追加] を選択します (これを + プラス ボタンにします)。
- 後の段階でコードで識別できるように、これに名前を付けます。 バー ボタン項目の名前を設定できるようにするには、ルート ビュー コントローラーにクラス名 (ItemViewController など) を付ける必要があることに注意してください。
TaskDetail ビュー コントローラー
詳細ビューには、さらに多くの作業が必要です。 テーブル ビューのセルをビューにドラッグし、ラベル、テキスト ビュー、ボタンを設定する必要があります。 次のスクリーンショットは、2 つのセクションを持つ、完成した UI を示しています。 1 つのセクションには 3 つのセル、3 つのラベル、2 つのテキスト フィールド、1 つのスイッチがあり、2 番目のセクションには 2 つのボタンを持つ 1 つのセルがあります。
完全なレイアウトを構築する手順は次のとおりです。
テーブル ビューを選択し、Property Pad を開きます。 次のプロパティを設定します。
- セクション: 2
- スタイル: グループ化
- 区切り: なし
- 選択: 選択なし
次に示すように、上部のセクションを選択し、[プロパティ] > [テーブル ビュー セクション] で [行] を「3」に変更します。
セルごとに、Properties Pad を開き、次の設定を行います。
- スタイル: カスタム
- 識別子: セルごとに一意識別子を選択します (例: "title"、"notes"、"done")。
- 必要なコントロールをドラッグして、スクリーンショットに表示されているレイアウトを生成します (UILabel、UITextField、UISwitch を正しいセルに配置し、ラベルを適切に設定します ([Title]、[Notes]、[Done]))。
2 番目のセクションで、[行] を「1」に設定し、セルの下部のサイズ変更ハンドルをつかんで高さを高くします。
識別子の設定: 一意の値にします (例:"save")。
背景の設定: クリア カラー。
次に示すように、2 つのボタンをセルにドラッグし、タイトルを適切に設定します ([Save] と [Delete])。
この時点で、セルとコントロールに制約を設定して、アダプティブ レイアウトを確保することもできます。
UIKit クラスの追加とコントロールの名前付け
ストーリーボードの作成には、最後の手順がいくつかあります。 最初に、[ID] > [名前] の下で各コントロールに名前を付けて、これらを後でコードで使用できるようにする必要があります。 次のように名前を付けます。
- Title UITextField: TitleText
- Notes UITextField: NotesText
- UISwitch: DoneSwitch
- Delete UIButton: DeleteButton
- Save UIButton: SaveButton
コードの追加
作業の残りの部分は、Mac または Windows 上の Visual Studio で C# を使用して実行します。 コードで使用されるプロパティ名には、上記のチュートリアルで設定したプロパティ名が反映されていることに注意してください。
まず、ID、Name、Notes、Done ブール値の値を取得して設定する方法を提供する Chores
クラスを作成し、これらの値をアプリケーション全体で使用できるようにします。
Chores
クラスに次のコードを追加します。
public class Chores {
public int Id { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}
次に、UITableViewSource
から継承する RootTableSource
クラスを作成します。
これとストーリーボード以外のテーブル ビューとの違いは、GetView
メソッドがセルのインスタンスを作成する必要がないという点です。theDequeueReusableCell
メソッドは常にプロトタイプ セルのインスタンスを返します (識別子が一致します)。
次のコードは RootTableSource.cs
ファイルのコードです。
public class RootTableSource : UITableViewSource
{
// there is NO database or storage of Tasks in this example, just an in-memory List<>
Chores[] tableItems;
string cellIdentifier = "taskcell"; // set in the Storyboard
public RootTableSource(Chores[] items)
{
tableItems = items;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return tableItems.Length;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
// in a Storyboard, Dequeue will ALWAYS return a cell,
var cell = tableView.DequeueReusableCell(cellIdentifier);
// now set the properties as normal
cell.TextLabel.Text = tableItems[indexPath.Row].Name;
if (tableItems[indexPath.Row].Done)
cell.Accessory = UITableViewCellAccessory.Checkmark;
else
cell.Accessory = UITableViewCellAccessory.None;
return cell;
}
public Chores GetItem(int id)
{
return tableItems[id];
}
RootTableSource
クラスを使用するには、ItemViewController
のコンストラクターに新しいコレクションを作成します。
chores = new List<Chore> {
new Chore {Name="Groceries", Notes="Buy bread, cheese, apples", Done=false},
new Chore {Name="Devices", Notes="Buy Nexus, Galaxy, Droid", Done=false}
};
ViewWillAppear
で、コレクションをソースに渡し、テーブル ビューに割り当てます。
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
TableView.Source = new RootTableSource(chores.ToArray());
}
ここでアプリを実行すると、メイン画面が読み込まれ、2 つのタスクのリストが表示されます。 タスクがタッチされると、ストーリーボードによって定義されたセグエにより、詳細画面が表示されますが、この時点ではデータは表示されません。
セグエで "パラメータを送信" するには、PrepareForSegue
メソッドをオーバーライドし、DestinationViewController
(この例では TaskDetailViewController
) でプロパティを設定します。 対象ビュー コントローラー クラスのインスタンスが作成されますが、ユーザーにはまだ表示されません。つまり、クラスにプロパティを設定できますが、UI コントロールを変更することはできません。
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "TaskSegue") { // set in Storyboard
var navctlr = segue.DestinationViewController as TaskDetailViewController;
if (navctlr != null) {
var source = TableView.Source as RootTableSource;
var rowPath = TableView.IndexPathForSelectedRow;
var item = source.GetItem(rowPath.Row);
navctlr.SetTask (this, item); // to be defined on the TaskDetailViewController
}
}
}
TaskDetailViewController
で、SetTask
メソッドはパラメータをプロパティに割り当て、ViewWillAppear で参照できるようにします。 コントロール プロパティは、PrepareForSegue
が呼び出されるときに存在しない可能性があるため、SetTask
で変更することはできません。
Chore currentTask {get;set;}
public ItemViewController Delegate {get;set;} // will be used to Save, Delete later
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
TitleText.Text = currentTask.Name;
NotesText.Text = currentTask.Notes;
DoneSwitch.On = currentTask.Done;
}
// this will be called before the view is displayed
public void SetTask (ItemViewController d, Chore task) {
Delegate = d;
currentTask = task;
}
セグエによって詳細画面が開かれ、選択したタスク情報が表示されます。 残念ながら、[Save] ボタンと [Delete] ボタンの実装はありません。 ボタンを実装する前に、これらメソッドを ItemViewController.cs に追加して、基になるデータを更新し、詳細画面を閉じます。
public void SaveTask(Chores chore)
{
var oldTask = chores.Find(t => t.Id == chore.Id);
NavigationController.PopViewController(true);
}
public void DeleteTask(Chores chore)
{
var oldTask = chores.Find(t => t.Id == chore.Id);
chores.Remove(oldTask);
NavigationController.PopViewController(true);
}
次に、ボタンの TouchUpInside
イベント ハンドラーを TaskDetailViewController.cs の ViewDidLoad
メソッドに追加する必要があります。 ItemViewController
に対する Delegate
プロパティ参照は具体的に作成されているため、SaveTask
と DeleteTask
を呼び出すことができます。これにより、これら操作の一環としてこのビューが閉じられます。
SaveButton.TouchUpInside += (sender, e) => {
currentTask.Name = TitleText.Text;
currentTask.Notes = NotesText.Text;
currentTask.Done = DoneSwitch.On;
Delegate.SaveTask(currentTask);
};
DeleteButton.TouchUpInside += (sender, e) => Delegate.DeleteTask(currentTask);
構築する残りの最後の機能は、新しいタスクの作成です。 ItemViewController.cs で、新しいタスクを作成し、詳細ビューを開くメソッドを追加します。 ストーリーボードからビューのインスタンスを作成するには、InstantiateViewController
メソッドと共にそのビューの Identifier
を使用します。この例では、"detail" です。
public void CreateTask ()
{
// first, add the task to the underlying data
var newId = chores[chores.Count - 1].Id + 1;
var newChore = new Chore{Id = newId};
chores.Add (newChore);
// then open the detail view to edit it
var detail = Storyboard.InstantiateViewController("detail") as TaskDetailViewController;
detail.SetTask (this, newChore);
NavigationController.PushViewController (detail, true);
}
最後に、ItemViewController.cs の ViewDidLoad
メソッドにナビゲーション バーのボタンを接続して呼び出します。
AddButton.Clicked += (sender, e) => CreateTask ();
これでストーリーボードの例が完成します。完成したアプリは次のようになります。
この例は、次の方法を示しています。
- データのリストを表示するために再利用することを目的としてセルが定義されているプロトタイプ コンテンツを含むテーブルを作成する。
- 静的コンテンツを含むテーブルを作成して入力フォームを構築する。 これには、テーブル スタイルの変更、セクション、セル、UI コントロールの追加が含まれています。
- セグエを作成し、
PrepareForSegue
メソッドをオーバーライドして、必要なパラメータをターゲット ビューに通知する方法。 Storyboard.InstantiateViewController
メソッドを使用してストーリーボード ビューを直接読み込む。