Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Xamarin逆引きTips

Xamarin逆引きTips

iOS/Androidの画面レイアウトを共通化するには?(Xamarin.Forms)

2014年6月4日

Xamarin 3がリリースされた。その新機能として注目されるXamarin.Formsの概要と、基本的な使い方、メリット/デメリットを解説する。Xamarin.Formsを使ってiOS/Android/Windows Phone間で画面レイアウトも共通化しよう。

奥山 裕紳(@amay077
  • このエントリーをはてなブックマークに追加

 5月28日にXamarinから大きな発表があった。「Xamarin 3」がリリースされたのだ。

 Xamarin 3では、大きなトピックとして、

  • Visual Studioにも対応したiOSデザイナー
  • 異なるプラットフォームで共通な画面開発を可能にするXamarin.Forms
  • F#言語やNuGetの正式サポート
  • Shared Projectへの対応

などが含まれるが、その中で最もインパクトの大きなXamarin.Formsについて取り上げる。

Xamarin.Formsとは?

 Xamarin.Formsを使用すると、異なるプラットフォーム(iOS/Android/Windows Phone)で、画面レイアウトおよびそれに関わる処理(つまりMVCパターンのView層)を、1つのソースコードで共通化できる。これまでXamarinの説明として「コアロジックは共通化できる。プラットフォーム固有機能や画面については共通化できない」と繰り返し述べてきたが、その前提が覆ることになり、かなりインパクトが大きな機能である。

 Xamarinでの画面開発が、全てXamarin.Formsに置き換えられたわけではない。従来通り、iOS/Androidのネイティブの画面開発手法(.storyboard.axmlレイアウトファイルなど)も引き続き利用できる。

 その仕組みはPhoneGapのようなWebView+HTMLによるものでも、Adobe AIRDelphi XEのようなUIパーツを独自レンダリングするものでもない、定義は共通であるが実行時にはプラットフォームごとのネイティブUI部品が使われる(方式的にはTitanium Mobileが近いと思われる)。

 画面のデザインは、C#言語によるコードまたはXAML(ザムル)で記述する。XAMLといっても、Windowsアプリ開発で使われるWPF(Windows Presentation Foundation)とは別のものだ。

 また、Xamarin 3では、Windows+Visual Studioを利用したものが強調されているが、Mac+Xamarin Studioでも使用可能である。

Xamarin.Formsを利用したアプリケーションを作成してみる

 Mac+Xamarin Studioを利用して、Xamarin.Formsを利用したアプリケーションを作成する手順を紹介する。Xamarin 3でUIが大きく刷新されたXamarin Studio 5.0を使用する。

1プロジェクトを作成する

 メニューバーの[ファイル]-[新規]-[ソリューション]から、[C#]-[Forms]-[Universal Xamarin.Forms Project (PCL)]を選択し、ソリューション名を「HelloForms」として[OK]ボタンを押す。ちなみに[Universal Xamarin.Forms Project (Shared Project)]でも同じことができる。Shared Project*1は、PCL(ポータブル・クラス・ライブラリ)を使わず、コードレベルでプラットフォーム間のコードを共有する1つの選択肢だ。

図1 Xamarin.Formsプロジェクト(&ソリューション)の作成

 作成されたソリューションのファイルツリーから、要点を解説する。

図2 Xamarin.Formsソリューションのファイルツリー

 まず、以下の3つのプロジェクトが作成される。

  • 「HelloForms」: iOSでもAndroidでも動作するPCLのライブラリだ
  • 「HelloForms.Android」「HelloForms.iOS」: それぞれのプラットフォームのネイティブアプリケーションであり、「HelloForms」プロジェクトを参照している

 図2で赤枠で囲んだ部分について、それぞれ説明しよう。

パッケージ ― Xamarin.Forms

 Xamarin.Formsを利用するために必要なNuGetパッケージ。既存のプロジェクトにFormsの機能を追加するには、[Add Packages]ダイアログ(=いわゆるNuGetパッケージマネージャー)から「Xamarin.Forms」を検索して追加することになる。

App.cs(共通の画面)

 画面レイアウトがC#言語で記述されているファイルだ。プロジェクト作成時点では、画面の中央に「Hello, Forms!」と表示するシンプルなものになっている。

C#
……省略……
public class App
{
  public static Page GetMainPage ()
  {   
    return new ContentPage { 
      Content = new Label {
        Text = "Hello, Forms !",
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.CenterAndExpand,
      },
    };
  }
}
……省略……
App.csファイルのひな型コード

GetMainPageメソッドは、後述のAndroid/iOSアプリのエントリポイントから呼び出される。

MainActivity.cs(Android)

 Androidアプリのエントリポイントとなるファイルだ。

C#
 
 
1
 
 
 
 
 
2
 
3
 
 
 
……省略……
[Activity (Label = "HelloForms.Android.Android", MainLauncher = true)]
public class MainActivity : AndroidActivity
{
  protected override void OnCreate (Bundle bundle)
  {
    base.OnCreate (bundle);

    Xamarin.Forms.Forms.Init (this, bundle);

    SetPage (App.GetMainPage ());
  }
}
……省略……
MainActivity.csファイルのひな型コード

 1で、基底クラスをAndroidActivityとしている。これはXamarin.Formsで提供されるクラスだ。

 次に、ActivityのOnCreateメソッドでは、通常、.axmlファイルを読み込んでSetContentするのが通常だが、それは行わず、2でXamarin.Fromsを初期化(=Initメソッド)している。

 続いて3で、App.csファイルで定義した画面(=GetMainPageメソッドの呼び出しにより取得)をSetPageメソッドで設定している。

 画面や画面遷移を全てXamarin.Formsに委ねるならば、MainActivity.csファイルで行うことは、これ以上はない。MainActivity.OnCreateメソッドは単なるエントリポイントとしてのみの機能だ。

AppDelegate.cs(iOS)

 AppDelegate.csファイルは、iOSアプリのエントリポイントであるが、Android同様、ここにXamarin.Forms向けのコードを記述する。

C#
 
 
 
 
 
 
 
 
1
 
 
 
2
 
 
 
 
 
 
……省略……
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
  UIWindow window;

  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
  {
    Forms.Init ();

    window = new UIWindow (UIScreen.MainScreen.Bounds);
    
    window.RootViewController = App.GetMainPage ().CreateViewController ();
    window.MakeKeyAndVisible ();
    
    return true;
  }
}
……省略……
AppDelegate.csファイルのひな型コード

 まず1で、Formsの初期化を行うのはAndroidと同様だ。

 続いて2で、App.csファイルから画面を取得してルートのViewControllerに設定している。

 こちらもXamarin.Formsだけを利用するならば、XXXViewController.csファイルは必要ない。

2取りあえず実行してみる

 まずはiOS/Android両方の環境で実行してみよう。図3を見ると分かるように、ただラベルが表示されるだけだが、確かに共通の画面デザインで動作することを確認できる。

図3 iOS(左)とAndroid(右)で実行した画面

UIパーツを利用する

 Xamarin.Formsが提供するUIパーツ群のうち、いくつかを使ってみよう。

 App.csファイルのコードを、下記のように修正する。

C#
public class App
{
  public static Page GetMainPage()
  {
    var datePicker = new DatePicker { };
    var button = new Button {
      Text = "Enter"
    };

    return new ContentPage {
      Content = new StackLayout {
        Children = {
          datePicker, 
          button
        },
        VerticalOptions = LayoutOptions.Center, 
        HorizontalOptions = LayoutOptions.Center
      }
    };

  }
}
DatePicker&Buttonコントロールを配置するように修正したApp.csファイルのコード

垂直(Vertical)と水平(Horizontal)のレイアウトオプションは、「拡大して中央(CenterAndExpand)」から「中央(Center)」に変更した。

 このコードは、StackLayoutという、UIパーツを縦または横に一列に並べて(=スタックさせて)表示させるコンテナー(AndroidでいうLinearLayout)に、日付ピッカーとボタンを配置したものだ。

 実行すると、次のようになる。

図4 DatePickerコントロールを追加した画面の実行結果(左:iOS、右:Android)

(Buttonコントロールも追加されているが、)

 DatePickerコントロールとして定義したUIパーツは、iOSとAndroid双方で、「ネイティブな日付選択ダイアログ」として実行されるのが確認できる。

画面遷移を行う

 App.csファイルをさらに修正して、新しい画面を定義し、画面遷移を行ってみよう。

C#
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
 
 
 
 
 
 
 
3
 
 
 
 
 
 
 
 
 
 
 
public class App
{
  public static Page GetMainPage()
  {   
    var datePicker = new DatePicker { };
    var button = new Button {
      Text = "Enter"
    };

    var page = new ContentPage {

      Content = new StackLayout {
        Children = {
          datePicker,
          button
        },
        VerticalOptions = LayoutOptions.Center,
        HorizontalOptions = LayoutOptions.Center
      }
    };

    var navPage = new NavigationPage(page);

    button.Clicked += (sender, e) =>
    {
      navPage.Navigation.PushAsync(App.GetSecondPage(datePicker.Date));
    };

    return navPage;
  }

  public static Page GetSecondPage(DateTime selectedDate)
  {
    return new ContentPage {
      Content = new Label {
        Text = selectedDate.ToString(),
        VerticalOptions = LayoutOptions.CenterAndExpand, 
        HorizontalOptions = LayoutOptions.CenterAndExpand, 
      },
      BackgroundColor = Color.Yellow
    };
  }
}
画面遷移を行うように修正したApp.csファイルのコード

* 2014/06/07更新 「navPage.Navigation.PushAsync(new NavigationPage(App.GetSecondPage(datePicker.Date)));」となっていた箇所を修正しました。お詫びして訂正させていただきます。

 まず、画面遷移を行う場合は、GetMainPageメソッドの戻り値で、NavigationPage(=Pageの派生クラス)オブジェクト(1)を返すようにする。これを行うことで、アプリケーションの左上にナビゲーションを表すアイコンが表示される(図5を参照。左上に[< Back]アイコンが表示されている)。

 2で、ボタンを押した時に、日付ピッカーで選択した日付けを渡しつつ、2つ目のページ(=GetSecondPageメソッドで取得)へ遷移している。そのSecondPageの定義が3だ。AndroidのActivityや、iOSのViewControllerを全く意識していないのが、コードから分かるだろう。

 これを実行すると、次のようになる。

図5 Xamarin.Formsによる画面遷移

まとめ

 Xamarin.Formsの最初の利用方法を簡単に解説した。Xamarin.Formsは発表まで存在が誰にも知られていなかったこともあり、情報はまだ少ないが、今回解説した画面レイアウトと画面遷移の他にも、MVVMフレームワークとしての機能(データバインディングやコマンドパターン、サービスロケーターなど)や、ネイティブの画面との相互連携の機能など、非常に豊富な機能を持ち、これだけで「アプリケーションフレームワーク」と呼べるほどの規模だ。これらについては今後順次、解説していきたい。

 現在はXamarin DevelopersのXamarin.Forms(英語)と、サンプルであるGitHubのxamarin-forms-samplesリポジトリが情報源だ。

【コラム】Xamarin.Formsを利用するメリット/デメリット

 メリットは再度言うまでもなく「複数のプラットフォームでView層を共通化できる」ことだ。上で述べた通り、Xamarin.FormsはMVVMフレームワークとしての機能も持ち合わせるので、プラットフォーム固有の機能を使わないならば、エントリポイント以外の処理は全て共通ライブラリに任せることができるだろう。ネイティブ画面との相互連携も可能なので、既存の資産と組み合わせることも可能だ。

 デメリットは他のクロスプラットフォーム開発ツールと同じで、プラットフォーム間に異なる機能を共通化するため、機能が最小公倍数になってしまうことだ。* 2014/06/11更新: お詫びして訂正させていださきます。例えば、iOSやAndroidでは、画面の端からスライドして表示するメニューがよく利用されるが(Androidでいう「Navigation Drawer」)、Xamarin.FormsにこのUIパーツは提供されない(これは MasterDetailPage で提供されていることが分かった。他の例えとしては画面を引っ張って更新する Pull-To-Refreshのパーツが挙げられる)、これはWindows PhoneのUIには、該当する機能が無いからだと、筆者は推測する。

 もう1つのデメリットは、Xamarin.Formsというフレームワークに「ロックイン」されることだ。Xamarin.iOS/Androidでは、画面の開発には、ネイティブの開発知識が利用できたが、Xamarin.Formsは新しい概念であるため、新しく学習する必要があるし、つぶしが利かない。

 Xamarinが、このXamarin.Formsを今後の開発方法の主軸として考えているのかは分からないが、現在のところは、ネイティブの画面開発の一部(単純な画面など)についてXamarin.Formsを採用するのが無難ではないかと思う。

※以下では、本稿の前後を合わせて5回分(第3回~第7回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Xamarin逆引きTips
3. Xamarin.iOSで画面をレイアウトするには?(Xcode利用/ビルトインiOS用UIデザイナー)

iOS用の画面レイアウトを、Xcodeで行う方法を解説。また、Xamarin StudioのビルドインUIデザイナーで行う方法も説明する。

Xamarin逆引きTips
4. Xamarin.Androidで画面遷移を行うには?

Xamarin.Androidで画面を追加する方法と、2つの画面間を遷移し、遷移先にデータを渡す方法、遷移先から返り値を得る方法を解説する。

Xamarin逆引きTips
5. 【現在、表示中】≫ iOS/Androidの画面レイアウトを共通化するには?(Xamarin.Forms)

Xamarin 3がリリースされた。その新機能として注目されるXamarin.Formsの概要と、基本的な使い方、メリット/デメリットを解説する。Xamarin.Formsを使ってiOS/Android/Windows Phone間で画面レイアウトも共通化しよう。

Xamarin逆引きTips
6. Xamarin.iOSでStoryboardとXamarin.Formsを併用するには?

Storyboardで作成したiOSアプリの一部の画面に、Xamarin.Formsを利用する方法を解説する。

Xamarin逆引きTips
7. Xamarin.AndroidでActivityとXamarin.Formsを併用するには?

iOSの場合と同じように、Androidアプリの一部の画面に、Xamarin.Formsを利用する方法を解説する。また、iOSとの挙動の違いやフラグメントとの併用についても言及する。

サイトからのお知らせ

Twitterでつぶやこう!