December 2015

Volume 30 Number 13

Xamarin - Xamarin.Forms によるクロスプラットフォーム UX のビルド

Keith Pijanowski

Xamarin を試すことを決めたところから、心躍る旅が始まります。1 つのプラットフォームをターゲットにする他の開発ツールとは異なり、Xamarin では 4 つの異なるプラットフォームにアクセスできます。Xamarin では、iOS、Android、Windows Phone、および MAC OS X をターゲットにするアプリケーションを、C# のスキルで開発できます。重要なのは、Xamarin により、完全にネイティブなエクスペリエンスが提供される点です。ネイティブなパフォーマンスが得られ、すべてのプラットフォームで完全な API にアクセスでき、ネイティブ UI を使用できます。今回は、Xamarin がサポートする iOS、Android、および Windows Phone という 3 つのモバイル プラットフォームに注目します。

Xamarin を使用するメリットが魅力的なのには多くの理由があります。1 つは、Xamarin のようなプラットフォームを使用することが単純におもしろいためです。Xamarin は、C# スキルを使えるだけでなく、上記のモバイル プラットフォームすべてについて詳しく学ぶ場にもなります。複数のワークスペース (Xcode、Android Studio/Eclipse、および Visual Studio) で複数の言語 (C#、Java、および Objective-C/Swift) を使用して作業する必要がなく、使い慣れた 1 つの環境 (Visual Studio) で 1 つの言語 (C#) を使用して作業できます。

Xamarin によるアプリ開発には財政上のメリットもいくつかあります。Xamarin では、1 つのソリューションを作成するだけで、1 つのバージョンのアプリを iOS、Android、Windows Phone、OS X に提供できます。これらのプラットフォームでコードとスキル セットを再利用できることで、大幅なコストの節約になり、生産性も向上します。アプリの収益化に関する基本的な経済学では、見込み顧客数が増えれば、有料顧客を獲得できる可能性も高くなるといわれています。Xamarin がサポートする 3 つのモバイル プラットフォームを合計すると、全世界のすべてのモバイル デバイスの 98%以上を占めることになります。

最後に、モバイル基幹業務 (LOB) アプリをビルドしている企業の場合、関連するプラットフォームすべてをターゲットにする 1 つのソリューションを作成できるため、各社員が自分のデバイスを作業に使用できるようになります。

従来型の Xamarin アプローチ

Xamarin で 3 つのモバイル プラットフォームをすべてサポートするソリューションの場合、これまでは最低でも 4 つのプロジェクト (ポータブル クラス ライブラリ (PCL) と、各プラットフォーム用のプラットフォーム固有プロジェクト) で構成されていました。PCL (共有コード プロジェクト) は、モデル、データ アクセス コード、およびビジネス ロジックを保持します。PCL 内のコードは他のプロジェクトから参照および再利用できます。ただし PCL は UI コードを保持しません。UI コードはプラットフォーム固有プロジェクトに保持します。従来型 Xamarin の目標は、ネイティブ プログラミング環境とその環境が表現するプラットフォームと同等の機能を提供することでした。Objective-C、Swift、または Java で可能なことはすべて、Xamarin と Visual Studio で C# を使って実現できます。必要な iOS、Android、および Windows Phone の API にはすべてアクセスできます。Xamarin はネイティブ API に 100% アクセスできます。このコードもプラットフォーム固有プロジェクト内に保持されます。

従来型 Xamarin アプローチは大量のコードを共有できるようにしますが、さらに多くのコードを共有する方法があります。

Xamarin.Forms の登場

Xamarin.Forms は、再利用に関する限界をさらに押し上げます。具体的には、Xamarin.Forms は従来型アプローチのメリットをすべて提供しながら、UI ロジックを全プラットフォームで再利用できるようにします。Xamarin.Forms ソリューションの構築も、従来型 Xamarin と同じ方法で行います。ただし、PCL に UI コードを保持できるようになります。プロジェクトを設定する目的と、プラットフォームごとに異なる画像などのリソースを保存する目的で、依然としてプラットフォーム固有プロジェクトも必要です。

Xamarin の開発者がこのようなことを試みたことは驚きではありません。iOS、Android、および Windows Phone は別々のアーキテクトによって構想され、異なる企業が開発したものですが、それでも各プラットフォームの UI には多くの共通点が見られます。ユーザーがコンテンツを閲覧するのは 1 ページずつです。コントロールの多くはどのプラットフォームも似ています。たとえば、テキスト ボックス、プッシュ ボタン、オプション ボタン、ラベル、リスト ビュー、画像の各コントロールは、各プラットフォームで比較的似ているものが使用されています。Xamarin.Forms には、ネイティブ UX を構築するために、合計 40 個のコントロール、7 種類のレイアウト、および 5 種類のページの種類が付属しています。

Xamarin.Forms が採用するプログラミング モデルは XAML/C# です。ページ、レイアウト、およびコントロールは XAML を使用して指定します。これは、Windows Phone プロジェクトでページを作成するのとほぼ同じ方法で行うことができます。コードだけで、ページ、レイアウト、およびコントロールを作成することもできます。どちらのテクニックも今回取り上げます。

Xamarin.Forms を使用すると難しくなる可能性があるのは、アプリの機能とコンテンツを編成する UI を設計して実装することです。これは、コードを最大限再利用しながら、同時に各プラットフォームでの使い心地に違和感のないアプリを作成できる方法で行う必要があります。そこで、Xamarin では、次の 5 種類のページを用意することで、共通の UI シナリオに対応します。基本コンテンツを表示するコンテンツ ページ、ナビゲーション機能を提供するナビゲーション ページ、画面の上部全体または下部全体にタブが配置されたページを作成するタブ ページ、2 つの情報ペインで概要データと詳細データを表示するマスター/詳細ページ、およびコンテンツを水平方向にスクロールできるページを作成するカルーセル ページの 5 種類です。今回は、この 5 種類のページをそれぞれ説明することで、各シナリオに対する Xamarin.Forms ソリューションを実際に示していきます。Xamarin.Forms に付属するページ レイアウトおよび UI コントロールについても、その過程で取り上げます。

コンテンツの表示

画面に基本コンテンツを表示するにはコンテンツ ページを使用します。図 1 は、ユーザーのフィードバックを受け取るために使用するページの XAML を示しています。

図 1 コンテンツ ページの XAML

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="https://schemas.microsoft.com/winfx/2009/XAML"
  x:Class="XamarinFormsTestHarness.FeedbackPage"
  Title="Feedback">
  <StackLayout Padding="10,10,10,10">
<Label Text="Name:" FontAttributes="None" FontSize="Medium" TextColor="#3498DB"/>
  <Entry Text="{Binding Name}" Placeholder="First and Last" Keyboard="Default"/>
  <Label Text="Email:" FontSize="Medium" TextColor="#3498DB" />
  <Entry Text="{Binding Email}" Placeholder="name@company.com" Keyboard="Email" />
  <Label Text="Feedback:" TextColor="#3498DB" FontSize="Medium"/>
  <Editor Text="{Binding Text}" HeightRequest="200" BackgroundColor="Gray"/>
    <Button x:Name="ButtonSubmitFeedback" Text="Submit"
      BackgroundColor="#3498DB"
      TextColor="White"
      Command="{Binding SaveFeedbackCommand}"/>
  </StackLayout>
</ContentPage>

図 1 の XAML は、スタック レイアウトを使用して、Label、Entry、Editor、Button などの基本コントロールを編成しています。ここで Xamarin.Forms ネイティブ機能の一例として使用している Entry は、iOS では UITextField、Android では EditText、Windows Phone では TextBox としてレンダリングされます。

ただし、Xamarin XAML は、Windows Phone XAML とは別物です。Windows Phone ページから XAML を取り出して Xamarin コンテンツ ページに落とし込むことはできません。たとえば、Margin プロパティと Padding プロパティを使用してコントロールの位置を微調整している方は、Xamarin.Forms コントロールの多くではこれらのプロパティが使用できないとことに不満を感じるかもしれません。また、コントロールとそのプロパティの多くは、Windows Phone の対応するコントロールやプロパティとは名前が違います。このような差異は新しい製品である証のようなものでしょう。多くの場合、こうした違いが事実だとしても、Xamarin が Windows Phone 開発者だけをターゲットにしているわけではないことを忘れないでください。Xamarin の目標は、あらゆるバックグラウンドのモバイル開発者をターゲットにする環境を提供することです。あるコントロールの名前が Windows Phone と違っているとしたら、Xamarin が使用する名前は Android か iOS で使われているのかもしれません。

コンテンツ ページは、他のすべての種類のページのビルディング ブロックです。カルーセル ページ、タブ ページ、ナビゲーション ページ、およびマスター/詳細ページは、コンテンツ ページを使用してそれぞれの UX をビルドします。

マスター/詳細のシナリオ

マスター/詳細のシナリオは、モバイル アプリでは非常に一般的です。したがって、Xamarin はこのシナリオに対処するために固有のページの種類を作成しました。マスター/詳細ページを使用して、アプリの機能やデータを整理することができます。たとえば、顧客と注文を管理するアプリでは、顧客リストをマスター ページに表示します。ユーザーが特定の顧客をタッチすると、その顧客が行った注文をすべて詳細ページに表示します。マスター/詳細ページは、アプリのメニュー オプションを表示する場合にも使用できます。この場合、マスター ページにアプリ内で使用できる機能を一覧し、各詳細ページで該当の機能を提供します。図 2 は、フィットネス アプリのメイン メニューに使用しているマスター/詳細ページのコンストラクター コードを示しています。図 3 は、そのマスター ページが各プラットフォーム上でどのようにレンダリングされるかを示しています。マスター ページは、iOS および Android では画面左側からスライドしてくるポップオーバー メニューとしてレンダリングされます。Windows Phone の場合は完全なページとしてレンダリングされます。ユーザーがオプションをタッチすると、該当ページに移動します。

図 2 マスター/詳細ページのコード

using System;
using Xamarin.Forms;
namespace XamarinFormsTestHarness
{
  public class MasterDetailControlPage : MasterDetailPage
  {
    public MasterDetailControlPage()
      {
      MenuPage menuPage = new MenuPage();
      menuPage.MenuListView.ItemSelected += (sender, e) =>
        MenuSelected(e.SelectedItem as MenuItem);
      // The Detail page must be set or the page will crash when rendered.
      this.Master = menuPage;
      this.Detail = new NavigationPage(new FeedbackPage());
      this.IsPresented = true;
      }
        ...
  }
}

iOS (左)、Android (中央)、Windows Phone (右) にレンダリングしたマスター/詳細ページ
図 3 iOS (左)、Android (中央)、Windows Phone (右) にレンダリングしたマスター/詳細ページ

図 2 のコードには、マスター/詳細ページを理解するうえで注目すべき要素がたくさんあります。まず、マスター/詳細ページは、実際にはコントローラーです。マスター/詳細ページには、マスター ページの UX は含まれておらず、詳細ページについても何も含まれていません。これらのページは別のファイル内にあります。マスター/詳細ページの役割は、ユーザーの要求に応じて正しいページを表示することです。図 3 のマスター ページは MenuPage という名前のコンテンツ ページです。MenuPage のインスタンスを作成し、マスター/詳細ページの Master プロパティに設定しています。説明を簡潔にするために、ここでは MenuPage の XAML を掲載していません。本稿付属のコード ダウンロードで確認してください。図 2 に示すマスター/詳細ページにも、詳細ページの UX は含まれていません。これらのページも別のファイル内にあります。ユーザーがメニュー オプションを選択したら、詳細ページのインスタンスを作成し、マスター/詳細ページの Detail プロパティに設定します。

マスター/詳細ページのコンストラクターでは、マスター ページと詳細ページの両方を設定します。両方のプロパティを設定しなければ、マスター/詳細ページは最初に表示される時点で無残なものになります。

IsPresented プロパティを理解しておくことも重要です。このプロパティは、マスター ページをユーザーに表示しているかどうかを示します。IsPresented プロパティが True に設定されていれば、マスター ページが表示されています。False に設定されていれば、現在の詳細ページが表示されています。

Windows Phone はマスター ページでのエクスペリエンス全体を単一のページ ビューとして扱います。言い換えると、ユーザーが詳細ビューにナビゲーションしても、Windows Phone はそれを標準ページ ナビゲーションとして扱いません。詳細ビューで [戻る] ボタンをタップすると、最初にマスター/詳細ページにナビゲーションされる前に表示していたページに戻ります。ユーザーはおそらくマスター/詳細ページのマスター ビューに戻ると考えるため、これは UX としては不適切です。この問題を回避するために、Xamarin.Forms は OnBackButtonPressed イベントをオーバーライドできるようにします。Windows Phone デバイスと Android デバイスにはすべてハードウェアの "戻る" ボタンが装備されているため、このイベントは Windows Phone と Android で発生します。iOS には "戻る" ボタンがないため、iOS でアプリを実行している場合は OnBackButtonPressed は発生しません。iOS では、ユーザーがマスター ページのアイコンをタップすることで、マスター ページに戻ることができます。マスター ページのアイコンはすべての詳細ページの左上に表示されます。マスター ページのアイコン プロパティを常に適切に設定しておくことが重要です。この設定をしていないと、ユーザーはアプリの詳細ページからマスター ページに戻る方法がなくなります。

アプリのナビゲーション

ナビゲーション ページは、iOS と Android のページ ナビゲーションを管理します。NavigationPages は、プッシュ/ポップ形式のナビゲーションです。新しいページをスタックの一番上にプッシュし、その後そのページをポップして取り除きます。Windows Phone OS はすべてのナビゲーションを追跡するうえ、すべての Windows Phone デバイスにはハードウェアの "戻る" ボタンが装備されています。したがって、ユーザーは常に直前の画面に戻ることができます。そのため、Windows Phone ではナビゲーション ページを使う効果はありません。

iOS と Android の場合、ナビゲーション ページは、ページの一番上に、現在ページのタイトルと、前のページのタイトルをリンクとして表示する UX を提供します。ルート ページはページのそのタイトルだけを含みます。ユーザーが前のページのタイトルにタッチすると、前のページに戻ります。

ナビゲーション ページを最も簡単に使用するには、コードでナビゲーション ページのインスタンスを作成して、ページをそのコンストラクターに渡します。以下のコード行を使用して、図 2 の詳細ページを作成します。

this.Detail = new NavigationPage(displayPage);

iOS を実行するデバイスにはハードウェアの "戻る" ボタンが装備されていないため、このナビゲーション ページが特に重要になります。ナビゲーション ページが提供する機能がなければ、ユーザーは 1 ページ戻ることができません。

タブ

タブ付きページの UI は、画面の一番上または一番下のいずれかに表示されるタブのリストとしてレンダリングされます。iOS の場合、タブのリストは画面の一番下に表示され、詳細エリアがその上に表示されます。タブ数が多く画面に収まりきらない場合、iOS のレンダリングでは "More" タブが表示され、このタブを使用して画面に収まりきらないタブにアクセスできます。Android の場合は画面の一番上を横切るようにタブが表示され、詳細エリアがその下に表示されます。タブ数が多く画面に収まりきらない場合、ユーザーはタブのコレクションを横方向にスクロールできます。Windows Phone の場合、タブ付きページはピボット ページとしてレンダリングされます。

タブ付きページを作成する方法は 2 種類あります。1 つは、図 4 に示すように、コンテンツ ページのオブジェクトをタブ付きページの Children プロパティに設定する方法です。この場合、Children のコレクションのエントリごとにタブが 1 つ作成されます。タブの作成には各ページの Title プロパティと Icon プロパティが使用されます。タブごとにルック アンド フィールが異なり、データが分かれている場合はこのテクニックが役に立ちます。図 5 は、図 4 のタブ付きページが各プラットフォーム上でどのようにレンダリングされるかを示しています。

図 4 Children プロパティを使用したタブ付きページの作成

using Xamarin.Forms;
namespace XamarinFormsTestHarness
{
  class TabbedControlPage : TabbedPage
    {
    public TabbedControlPage()
      {
      this.Title = "My Workouts";
      this.Children.Add(new ThisWeek());
      this.Children.Add(new LastWeek());
      this.Children.Add(new ThisMonth());
      this.Children.Add(new LastMonth());
      this.Children.Add(new All());
      }
    }
}

iOS (左)、Android (中央)、および Windows Phone (右) でレンダリングされたタブ付きページ
図 5 iOS (左)、Android (中央)、および Windows Phone (右) でレンダリングされたタブ付きページ

タブ付きページを作成するもう 1 つの方法は、同じクラスからインスタンスを作成したオブジェクトのリストをタブ付きページの ItemsSource プロパティに割り当てることです。この場合、リスト内のオブジェクトごとにタブが 1 つ作成されます。その後、このタブ付きページの ItemTemplate プロパティに、DataTemplate 設定する必要があります。DataTemplate はコンテンツ ページから作成します。このコンテンツ ページではデータ バインドを使用して、ItemSource プロパティ内の対応するオブジェクトからデータを取得します。重要なのは、コンテンツ ページの Title プロパティを、バインドしているオブジェクトのプロパティにバインドすることです。タブのラベルは、この Title プロパティを使用して作成されます。このコンテンツ ページの残りの部分を使用して、バインドしているオブジェクトの他のプロパティにバインドすることもできます。このテクニックは、各タブの UX が同じで、異なるデータを表示するタブ付きページに最適です。

カルーセル

カルーセル ページの UI では、画面を左右にスワイプして、異なるページのコンテンツを表示できます。Windows Phone の開発者にとってのカルーセル ページは、パノラマと考えてかまいません。カルーセル ページには、タブ付きページと同様、Children プロパティがあります。カルーセル ページを作成するには、カルーセル ページの Children プロパティに、コンテンツ ページのオブジェクトを設定します。すると、各コンテンツ ページが、1 つのコンテンツ画面としてレンダリングされるようになります。カルーセル ページでは、各コンテンツ ページの Title プロパティを使用しません (この点は、各 Title がタブのタイトルに使用されるタブ付きページと異なります)。そのため、画面ごとにラベルが必要な場合は、コンテンツ ページのコンテンツの一部として手作業でラベルを実装します。図 6 は、このページが各プラットフォームでどのようにレンダリングされるかを示しています。iOS と Android では、現在のビューの左右にコンテンツがあることをユーザーに伝える明確な手がかりがありません。Windows Phone では、ページ タイトルの一部を表示することで、これを表現しています。そのため、iOS と Android でカルーセルを使用する場合は注意が必要です。ユーザーがアプリの重要なコンテンツに気が付かない可能性があります。

iOS (左)、Android (中央)、および Windows Phone (右) でレンダリングされたカルーセル ページ
図 6 iOS (左)、Android (中央)、および Windows Phone (右) でレンダリングされたカルーセル ページ

3 つのプラットフォームをターゲットにするデザイン

3 つのプラットフォームに精通していると、おそらくこの時点で気付くことがあります。つまり、Xamarin.Forms の各ページの種類は、ある 1 つのプラットフォームに必要な UI シナリオを表していて、残りの 2 つのプラットフォームでは独創的な実装が必要になります。たとえば、前のページへのリンクが用意されるナビゲーション ページは、iOS のデバイスに "戻る" ボタンが装備されていないことから、iOS に戻るボタンの機能を提供するために必要です。ナビゲーション ページは Android でも同じようにレンダリングされます。Android デバイスには "戻る" ボタンが装備されているとしても、直前にアクセスしたページへのリンクを現在ページの一番上に用意するのは Android でも一般的な UI 構造です。

同様に、タブは iOS でも Android でも非常に頻繁に使用されます。そのため、Xamarin.Forms はツールボックスにこの UI 構造を用意する必要がありました。Windows Phone ではタブはピボット ページとしてレンダリングされます。ピボット ページは Windows Phone OS に不可欠の要素です。

マスター/詳細ページは、ポップオーバー パネルを提供します。ポップオーバー パネルは iOS と Android でときどき使用されます。

最後に、Windows Phone にはパノラマ ページという考え方があります。パノラマ ページはアプリのホームページとして使用するのに最適です。パノラマ ページの目的はアプリの概要を提供することにあり、適切にデザインされたパノラマ ページは雑誌の表紙のような働きをします。ユーザーは、パノラマ ページを利用して、アプリの内容を簡単に把握します。説得力のある方法で仕上げれば、パノラマ ページでユーザーをアプリに引き付けることができるでしょう。コンテンツの画面を横方向にスワイプするという考え方は、iOS と Android ではあまりなじみのある考え方ではありません。そのため、Xamarin.Forms アプリでカルーセル ページを使用する場合は慎重を期す必要があります。

Xamarin.Forms プラットフォームは進化中なので、ページの種類がさらに追加されるのは間違いありません。Xamarin 開発者は、デザインに責任を持って、各ページの種類を確認し、アプリがターゲットにするすべてのプラットフォームにとって、そのページの種類が適切かどうかを判断してください。

まとめ

Xamarin では、コードを共有するネイティブ アプリをビルドするために、従来型 Xamarin と Xamarin.Forms という 2 つのメイン アプローチを用意しています。適切なアプローチの選び方はビルドのターゲットによって異なります。

アプリでプラットフォームごとに専用の操作を必要とし、なおかつプラットフォーム固有 API を多数活用する場合は従来型の Xamarin アプローチを使用します。従来型 Xamarin では、プラットフォームごとにカスタマイズした UI をビルドすることもできます。

Xamarin.Forms は、単一の共有コード ベースを使用してネイティブ アプリをビルドするためのフル装備のフレームワークです。データ入力アプリのプロトタイプのビルドや、プラットフォーム固有の機能をほとんど必要としないアプリのビルドには、Xamarin.Forms の使用を検討します。プラットフォームごとにカスタム UI を用意することよりも、コードを共有する方が重要なプロジェクトも、Xamarin.Forms の使用が適しています。


Keith Pijanowski は、エンジニア兼起業家の仕事人間です。ソフトウェア業界で 20 年以上の経験があり、新興企業にも大企業にも勤め、コード作成から事業開発まで、さまざまな業務に携わってきました。彼の連絡先は keithpij@msn.com (英語) または Twitter (twitter.com/keithpij、英語) です。

この記事のレビューに協力してくれた技術スタッフの Pierce Boggan (Xamarin) に心より感謝いたします。