次の方法で共有


iOS Designer でのテーブルの操作

ストーリーボードは、iOS アプリケーションを作成するための WYSIWYG 手段であり、Mac と Windows 上の Visual Studio 内でサポートされています。 ストーリーボードの詳細については、「ストーリーボードの概要」ドキュメントを参照してください。 ストーリーボードを使用すると、テーブルのセル レイアウトを編集することもできます。これにより、テーブルとセルを使用した開発が簡単になります。

iOS Designer でテーブル ビューのプロパティを構成する場合、選択できるセル コンテンツには、動的または静的プロトタイプ コンテンツの 2 種類があります。

動的プロトタイプ コンテンツ

プロトタイプ コンテンツを含む UITableView は通常、データのリストを表示することを目的としています。この場合、1 つのプロトタイプ セル (または複数のセルを定義できるために複数のセル) がリスト内の各項目に再利用されます。 セルのインスタンスを作成する必要はありません。セルは、UITableViewSourceDequeueReusableCell メソッドを呼び出すことによって GetView メソッドで取得されます。

静的コンテンツ

静的コンテンツを含む UITableView を使用すると、テーブルをデザイン サーフェイス上で直接設計できます。 セルは、テーブルにドラッグし、プロパティを変更してコントロールを追加することでカスタマイズできます。

ストーリーボード駆動型アプリの作成

StoryboardTable の例には、ストーリーボードで両方の種類の UITableView を使用する単純なマスター詳細アプリが含まれています。 このセクションの残りの部分では、完成すると次のようになる小さな To Do リストの例を作成する方法について説明します。

画面の例

ユーザー インターフェイスはストーリーボードを使用して構築され、両方の画面で UITableView が使用されます。 メイン画面ではプロトタイプ コンテンツを使用して行をレイアウトし、詳細画面では静的コンテンツを使用してカスタム セル レイアウトを使用してデータ入力フォームを作成します。

チュートリアル

Visual Studio で [(作成) 新しいプロジェクト…] > [単一ビュー アプリ (C#)] を使用して新しいソリューションを作成し、これに StoryboardTables という名前を付けます。

[新しいプロジェクトの作成] ダイアログ

このソリューションでは、いくつかの C# ファイルを、既に作成されている Main.storyboard ファイルと共に開きます。 Main.storyboard ファイルをダブルクリックして iOS Designer で開きます。

ストーリーボードの変更

ストーリーボードは、次の 3 つの手順で編集します。

  • 最初に、必要なビュー コントローラーをレイアウトし、プロパティを設定します。
  • 2 番目に、オブジェクトをビューにドラッグ アンド ドロップして UI を作成します。
  • 最後に、必要な UIKit クラスを各ビューに追加し、さまざまなコントロールに名前を付けてコードで参照できるようにします。

ストーリーボードが完了したら、コードを追加してすべてを動作させることができます。

ビュー コントローラーのレイアウト

ストーリーボードに対する最初の変更は、既存の Detail ビューを削除し、UITableViewController に置き換えることです。 次のステップを実行します。

  1. ビュー コントローラーの下部にあるバーを選択して削除します。

  2. ナビゲーション コントローラーテーブル ビュー コントローラーをツールボックスからストーリーボードにドラッグします。

  3. 先ほど追加した 2 番目のテーブル ビュー コントローラーにルート ビュー コントローラーからセグエを作成します。 セグエを作成するには、Control キーを押しながら Detail セルから、新しく追加した UITableViewController にドラッグします。 [セグエの選択][表示] オプションを選択します。

  4. 作成した新しいセグエを選択し、このセグエをコードで参照するための識別子を付けます。 セグエをクリックし、次のようにプロパティ パッド識別子TaskSegue を入力します。
    プロパティ パネルでのセグエの名前付け

  5. 次に、2 つのテーブル ビューを選択し、プロパティ パッドを使用してこれらを構成します。 ビュー コントローラーではなくビューを選択するようにしてください。ドキュメント アウトラインを使用すると、選択の役に立ちます。

  6. ルート ビュー コントローラーを [コンテンツ: 動的プロトタイプ] に変更します (デザイン サーフェイスのビューには、プロトタイプ コンテンツというラベルが付けられます)。

    Content プロパティを動的プロトタイプに設定する

  7. 新しい UITableViewController[コンテンツ: 静的セル] に変更します。

  8. 新しい UITableViewController には、クラス名と識別子が設定されている必要があります。 ビュー コントローラーを選択し、プロパティ パッド[クラス] に「TaskDetailViewController」と入力します。これにより、ソリューション パッドに新しい TaskDetailViewController.cs ファイルが作成されます。 次の例に示すように、[ストーリーボード ID] として「detail」と入力します。 これは後で C# コードでこのビューを読み込むために使用されます。

    ストーリーボード ID の設定

  9. ストーリーボードのデザイン サーフェイスは次のようになります (ルート ビュー コントローラーのナビゲーション項目のタイトルが "Chore Board" に変更されました)。

    デザイン画面

UI を作成する

ビューとセグエが構成されたので、ユーザー インターフェイス要素を追加する必要があります。

ルート ビュー コントローラー

まず、マスター ビュー コントローラーでプロトタイプ セルを選択し、次に示すように [識別子] を「taskcell」として設定します。 これは後でコードで、この UITableViewCell のインスタンスを取得するために使用されます。

セル識別子の設定

次に、次に示すように、新しいタスクを追加するボタンを作成する必要があります。

ナビゲーション バーのバー ボタン項目

次の操作を行います。

  • ツールボックスから [バー ボタン項目]ナビゲーション バーの右側にドラッグします。
  • Properties Pad[バー ボタン項目] の下で、[識別子: 追加] を選択します (これを + プラス ボタンにします)。
  • 後の段階でコードで識別できるように、これに名前を付けます。 バー ボタン項目の名前を設定できるようにするには、ルート ビュー コントローラーにクラス名 (ItemViewController など) を付ける必要があることに注意してください。

TaskDetail ビュー コントローラー

詳細ビューには、さらに多くの作業が必要です。 テーブル ビューのセルをビューにドラッグし、ラベル、テキスト ビュー、ボタンを設定する必要があります。 次のスクリーンショットは、2 つのセクションを持つ、完成した UI を示しています。 1 つのセクションには 3 つのセル、3 つのラベル、2 つのテキスト フィールド、1 つのスイッチがあり、2 番目のセクションには 2 つのボタンを持つ 1 つのセルがあります。

詳細ビューのレイアウト

完全なレイアウトを構築する手順は次のとおりです。

テーブル ビューを選択し、Property Pad を開きます。 次のプロパティを設定します。

  • セクション: 2
  • スタイル: グループ化
  • 区切り: なし
  • 選択: 選択なし

次に示すように、上部のセクションを選択し、[プロパティ] > [テーブル ビュー セクション][行] を「3」に変更します。

上部のセクションを 3 行に設定する

セルごとに、Properties Pad を開き、次の設定を行います。

  • スタイル: カスタム
  • 識別子: セルごとに一意識別子を選択します (例: "title"、"notes"、"done")。
  • 必要なコントロールをドラッグして、スクリーンショットに表示されているレイアウトを生成します (UILabelUITextFieldUISwitch を正しいセルに配置し、ラベルを適切に設定します ([Title]、[Notes]、[Done]))。

2 番目のセクションで、[行] を「1」に設定し、セルの下部のサイズ変更ハンドルをつかんで高さを高くします。

  • 識別子の設定: 一意の値にします (例:"save")。

  • 背景の設定: クリア カラー

  • 次に示すように、2 つのボタンをセルにドラッグし、タイトルを適切に設定します ([Save][Delete])。

    下部セクションに 2 つのボタンを設定する

この時点で、セルとコントロールに制約を設定して、アダプティブ レイアウトを確保することもできます。

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.csViewDidLoad メソッドに追加する必要があります。 ItemViewController に対する Delegate プロパティ参照は具体的に作成されているため、SaveTaskDeleteTask を呼び出すことができます。これにより、これら操作の一環としてこのビューが閉じられます。

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.csViewDidLoad メソッドにナビゲーション バーのボタンを接続して呼び出します。

AddButton.Clicked += (sender, e) => CreateTask ();

これでストーリーボードの例が完成します。完成したアプリは次のようになります。

完了したアプリ

この例は、次の方法を示しています。

  • データのリストを表示するために再利用することを目的としてセルが定義されているプロトタイプ コンテンツを含むテーブルを作成する。
  • 静的コンテンツを含むテーブルを作成して入力フォームを構築する。 これには、テーブル スタイルの変更、セクション、セル、UI コントロールの追加が含まれています。
  • セグエを作成し、PrepareForSegue メソッドをオーバーライドして、必要なパラメータをターゲット ビューに通知する方法。
  • Storyboard.InstantiateViewController メソッドを使用してストーリーボード ビューを直接読み込む。