Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.Androidで画面をレイアウトするには?

2014年5月14日

Xamarin.Androidでの画面のレイアウトの仕組みは、ネイティブのAndroidとほぼ同じ。そのレイアウト方法をネイティブでの手順と比較しながら解説する。

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

 Xamarin.Androidでの画面のレイアウトは、ネイティブのAndroidとほとんど同じ仕組みだ。これは、前回説明した通り、XamarinのAPIは、View関連については各プラットフォームのAPIのラッパーであるためだ。

 今回は、ネイティブAndroid(以下、「ネイティブ」と記載)での手順と比較しながら、Xamarin.Androidで画面レイアウトを行う方法を解説する。

画面に関連するファイル群

 まずは、Xamarin StudioでXamarin.Androidのプロジェクトを作成した直後のファイルツリーを見てみよう。

図1 Xamarin.Androidプロジェクトを作成した直後のXamarin Studio

 読者がAndroid開発者なら、見慣れたディレクトリやファイルが並んでいることが分かるだろう。ただし命名は、.NETの文化に習って「アッパーキャメルケース」だ。

 以下、代表的なファイルについて解説する。

1AndroidManifest.xml

 これはAndroidアプリケーションのメタ情報を記述するためのファイルである。Xamarin.Androidで作成されるファイルの内容は、以下のようになっている。

XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="HelloWorld.HelloWorld">
  <uses-sdk />
  <application android:label="HelloWorld">
  </application>
</manifest>
AndroidManifest.xmlファイルの初期内容

 ネイティブでのAndroidManifest.xmlファイルと同じ仕様であるが、画面に関する記述(=<activity/>~</activity>)が一切ないことに気付くだろう。Xamarin.Androidでは、画面に関するメタ情報は、実装クラス(例:MainActivity)の属性として記述する。

 ネイティブAndroidでは、「画面のクラスは追加したが、AndroidManifest.xmlファイルに追記し忘れたために、画面が表示されない」というミスを起こす可能性があった。だが、Xamarin.Androidではその心配はない(ネイティブでもIDEの進化により、このようなミスはだいぶ減ってはいるが)。

2MainActivity.cs

 画面の実装クラスであるMainActivity.csファイルのコードは次のようになっている。

C#
1
 
 
 
 
 
 
 
 
2
 
3
 
4
 
 
 
 
 
[Activity(Label = "HelloWorld", MainLauncher = true)]
public class MainActivity : Activity
{
  int count = 1;

  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);

    SetContentView(Resource.Layout.Main);

    Button button = FindViewById<Button>(Resource.Id.myButton);

    button.Click += delegate
    {
      button.Text = string.Format("{0} clicks!", count++); 
    };
  }
}
MainActivity.csファイルのコード(上部の名前空間に関する部分は省略)

 1で、1で説明した画面に関するメタ情報の定義を行っている。ここではActivityのタイトルと、起動時に表示すること示すMainLauncher=trueを設定している。設定可能な属性の情報は、Xamarin Developer Centerの「Working with AndroidManifest.xml(英語)」を参考にしてほしい。

 2で、画面のレイアウト情報を設定している。ネイティブではsetContentView(R.layout.activity_main)と記述するところだ。RからResourceに、layoutLayoutに変わっているだけだ。

 3では、レイアウトに定義したView(ここではButtonウィジェット)のインスタンスを得ている。これもネイティブとほぼ同じだ。

 4では、ボタンが押された時の処理を記述している。これはXamarinの特徴的なところで、ネイティブでsetOnClickListenerなどのリスナークラスを設定するAPIは、可能な限り、このような.NET Frameworkの「イベント」に置き換えられている。これにより複数のハンドラーを設定できたり、Javaに比べて簡潔な記述が可能になったりしている。

 34は、C#のコードとしてはまだ少し冗長で、以下のように短縮できる。

C#
3
 
4
 
var button = FindViewById<Button>(Resource.Id.myButton);

button.Click += (s, e) 
  => button.Text = string.Format("{0} clicks!", count++);
より短縮したコードの書き方

 ローカル変数は、型を指定しなくてもvarキーワードを置くことで右辺より型が自動的に推測される。イベントハンドラーは、ラムダ式を利用すれば、1行で簡潔に書ける。このような言語機能は、Xamarinを採用する大きなメリットの1つであるので積極的に活用していきたい。

3Main.axml

 これは画面のレイアウトを記述したファイルだ。ネイティブで利用するXMLファイル(例:activity_main.xml)ファイルと全く同じ仕様のファイルである。そのため、ほとんどの場合で、ネイティブで利用していたものがXamarin.Androidでもそのまま使用できるだろう。ただしファイルの拡張子が.axmlとなる(一見、XAML(ザムル)と間違えるが全くの別物だ)。

画面レイアウトの方法

 .axmlファイルをダブルクリックすると、図2のようなUIデザイナーが起動する。

図2 .axmlファイルを開いたところ(Android用のUIデザイナー)

 Android用のUIデザイナーとXMLのコードエディターが、画面下部の[コンテンツ]/[ソース]タブで切り替えられる。

 ネイティブのEclipse+ADTに搭載されるUIデザイナーと似たルック&フィールになっているので、それほど戸惑わずに利用できるだろう。ここでは基本的な使い方についてのみ説明する。

1Toolboxから追加したいViewを画面上にドラッグ&ドロップする

 試しに、入力可能なテキスト要素である[Text Fields]グループ内の[Plain Text]を画面上の[Hello World]ボタンの下に配置してみよう(図3)。

図3 ドラッグ&ドロップによるViewの配置

 Main.axmlファイルのルート要素は、<LinearLayout>orientation=verticalになっているので、要素は縦に並ぶ。ドラッグ中に、どこにViewが挿入されるかが青線で示されるのですぐに分かるだろう。追加すると以下のような画面となる。

図4 Viewを追加した後の表示例

 このときのMain.axmlファイルは、以下のようになっている。

XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <Button
    android:id="@+id/myButton"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />
  <EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/editText1" />
</LinearLayout>
Viewを追加した後のMain.axmlファイルの内容

[Plain Text]をドラッグ&ドロップして配置した結果、要素が挿入されている。

2Viewの属性を設定する

 追加した<EditText>要素の属性を、[プロパティ]ウィンドウで次のように変更してみよう。

  • [Id]: @+id/editMyNumber
  • [Hint]: Input your number
  • [Input Type]: number

 変更後、UIデザイナーとMain.axmlファイルは、以下のように変わっているはずだ。

図5 Viewの属性を変更した結果(UIデザイナー)
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <Button
    android:id="@+id/myButton"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />
  <EditText
    android:id="@+id/editMyNumber"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Input your number" 
    android:inputType="number" />
</LinearLayout>
Viewの属性を変更した結果(Main.axml)

【コラム】レイアウトにおけるリテラルの使用について

 この例ではHint属性にリテラル文字列を直接指定しているが、このようなリテラル値はStrings.xmlColors.xmlといったリソースファイルに定義し、その参照を利用すべきである。

3Viewを利用するコードを記述する

 ボタンを押した時に、入力した数値をToastで表示する機能を実装してみよう。

C#
[Activity(Label = "HelloWorld", MainLauncher = true)]
public class MainActivity : Activity
{
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);

    SetContentView(Resource.Layout.Main);

    var editMyNumber = FindViewById<EditText>(Resource.Id.editMyNumber);
    var button = FindViewById<Button>(Resource.Id.myButton);

    button.Click += (s, e) => 
    {
      Toast.MakeText(this, "Your number is " + editMyNumber.Text, ToastLength.Short).Show();
    };
  }
}
ボタンクリック時の処理の実装例

 .axmlファイルでEditTextに追加した際に設定したID editMyNumberを指定してFindViewByIdメソッドを呼び出すと、EditTextのインスタンスが取得できる。あとはボタンが押された時のコードを少し修正して、Toastを表示している。

 このサンプルを動作させると図6のようになる。

図6 作成したサンプルの実行

入力された番号を通知するトーストが表示されている。

まとめ

 Xamarin.AndroidのUIデザイナーを使って、Viewを追加し、それをコードから利用する例を紹介した。UIデザイナーは、機能はもっと豊富なので、詳しい使い方はXamarin Developer Centerの「Designer Overview(英語)」を見てほしい。

 また、このUIデザイナーは完成度の高い機能ではあるものの、本家であるEclipse+ADTやAndroid StudioのUIデザイナーと比べると若干の見劣りを感じることもあるだろう。その場合は、画面レイアウト作成はネイティブのツールで行い、出来上がったXMLファイルをXamarin.Androidで使用することもできる。実際、筆者がUIレイアウトを行う際は、UIデザイナーよりもXMLコードをじか書きすることに慣れているが、Xamarin.AndroidのXMLコードエディターよりも、Eclipse+ADTの方が、入力補完がよく利くので多用している。

 Viewを使うコードも、ネイティブとほとんど変わりがないが、C#/.NET Frameworkの機能を生かして、より簡潔な記述ができるので、ぜひ使ってみてほしい。

【コラム】Fragmentについて

 最近のネイティブの開発では、「Fragment」と呼ばれる「View要素をグループ化して別部品にする機能」を使うことが推奨されており、Eclipse+ADTでAndroidプロジェクトを作成すると、Fragmentを使用するコードが生成されるようになった。

 このため、単純な“HelloWorld”アプリでも、ネイティブとXamarin.Androidでは構成に違いが見られるので注意してほしい。具体的には、Activityのレイアウトとして行っていたものは、Fragmentのレイアウトとなり、そのFragmentをActivityが読み込む形になっている。

 レイアウトファイルの仕様に変更はないので、Fragmentのレイアウト作成にもXamarin.AndroidのUIデザイナーは利用可能である。この辺りは、Fragmentを利用するTipsの回で述べたいと思う。

 次回は、Xamarin.iOSでの画面レイアウトについて紹介する予定だ。

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

1. Xamarin.Android/Xamarin.iOSを利用するには?

C#でAndroid/iOSアプリを開発できるXamarinの実践TIPSの連載がスタート。TIPSの方向性や読者対象を示し、Xamarinの概要やインストールについて解説する。

2. 【現在、表示中】≫ Xamarin.Androidで画面をレイアウトするには?

Xamarin.Androidでの画面のレイアウトの仕組みは、ネイティブのAndroidとほぼ同じ。そのレイアウト方法をネイティブでの手順と比較しながら解説する。

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

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

4. Xamarin.Androidで画面遷移を行うには?

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

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

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

サイトからのお知らせ

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • 日本マイクロソフト株式会社
  • グレープシティ株式会社