かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Xamarin.Androidで画面遷移してみよう

過去記事

画面遷移してみよう

ここでは、Andoridの画面遷移について説明します。Andoridでは、画面遷移にIntentというものを使います。このIntentは、とても汎用的なメッセージング機構でサービスとよばれるバックグラウンドで実行される処理の起動や、ここで説明する別画面(Activity)の起動などができます。さらには、別アプリのActivityやサービスなども起動することもできます。Intentは、簡単に言うと宛先とデータを持った入れ物です。それを投げつけると、それに応答するように設定されたものが応答します。 では、画面遷移するアプリケーションを作ってIntentの簡単な使い方を見てみたいと思います。NavigationAppという名前でAndroidのBlank Appを作成します。そして、新規作成から、ActivityをNextActivityという名前で作成します。NextActivityに対応する見た目を定義するaxmlをResources/layoutフォルダにNext.axmlという名前で作成します。 Main.axmlにEditTextを追加します。idは@+id/GreetMessageにしました。axmlを以下に示します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="25px"
    android:minHeight="25px">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/GreetMessage" />
</LinearLayout>

メニューの定義

ここで、画面遷移のほかに新しいことをやってみたいと思います。メニューをアクションバーに追加してみたいと思います。メニューは、ActivityのOnCreateOptionsMenuメソッドをオーバーライドしてMenuInflaterのInflateメソッドを使うことで作成します。メニューは、Resources/menuフォルダにXMLで定義します。ここでは、MainMenu.xmlという名前で以下のようなXMLを定義しました。

<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/NavigateMenu"
        android:title="@string/NavigateMenuText" 
        android:onClick="NavigateMenuClick"
        android:showAsAction="always"
        android:icon="@drawable/Icon"/>
</menu>

android:idに識別用のIDを定義し、android:titleにメニューを長押ししたときに表示されるテキストを指定し、android:onClickに選択時に実行されるメソッドを指定し、android:showAsActionにアクションバーへの表示方法を指定し、android:iconにアイコンを指定します。android:showAsActionには、バーには表示しないnever、余裕があればバーに表示するifRoom、常に表示するalways、android:titleのテキストを表示するwithTextなどがあります。その他の完全な属性の定義については、以下のページを参照してください。

itemは複数定義することが出来ます。また、menu/menu/itemのようにメニューにメニューを入れ子にすることもできます。 上記メニューを画面に表示します。MainActivityのOnCreateOptionsMenuでMenuInflaterのInflateメソッドでメニューのリソースと引数で渡されたIMenuを結びつけます。そして、NavigateMenuClickメソッドを定義して選択時のアクションを定義します。NavigateMenuClickは、Java側にメソッドを教えるためにMono.Android.dllアセンブリ(追加で参照が必要)に定義されているJava.Interop.Export属性で名前を指定します。コードは以下のようになります。

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Util;
using Java.Interop;

namespace NavigationApp
{
    [Activity(Label = "NavigationApp", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            this.SetContentView(Resource.Layout.Main);
        }

        public override bool OnCreateOptionsMenu(IMenu menu)
        {
            this.MenuInflater.Inflate(Resource.Menu.MainMenu, menu);
            return true;
        }

        [Export(nameof(NavigateMenuClick))]
        public void NavigateMenuClick(IMenuItem menuItem)
        {
            Log.Debug("MainActivity", $"Clicked: {menuItem.TitleFormatted}");
        }
    }
}

これで、実行すると以下のような画面が表示され、アクションバーのメニューを選択することで出力ウィンドウにメッセージが表示されます。

f:id:okazuki:20160819220438p:plain

画面遷移

メニューを選択したときに画面遷移を行うようにします。以下のようにNextActivityを対象としたIntentを作成して、PutExtraメソッドでIntentにデータを設定してStartActivityメソッドで次の画面を起動します。

[Export(nameof(NavigateMenuClick))]
public void NavigateMenuClick(IMenuItem menuItem)
{
    // NextActivityへのIntentを作成して
    var intent = new Intent(this, typeof(NextActivity));
    // データを詰めて
    intent.PutExtra("Message", this.FindViewById<EditText>(Resource.Id.GreetMessage).Text);

    this.StartActivity(intent);
}

NextActivity用の画面であるNext.axmlではTextViewを1つおいて受け取ったメッセージを表示したいと思います。axmlの内容を以下に示します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="25px"
    android:minHeight="25px">
    <TextView
        android:text="Text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/TextViewGreetMessage" />
</LinearLayout>

画面遷移先のNextActivityでは、Intentプロパティを通じて渡されたIntentが参照できます。ここからGetStringExtraメソッドで渡された値を参照してTextViewに設定しています。

using Android.App;
using Android.OS;
using Android.Widget;

namespace NavigationApp
{
    [Activity(Label = "NextActivity")]
    public class NextActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            this.SetContentView(Resource.Layout.Next);

            var textView = this.FindViewById<TextView>(Resource.Id.TextViewGreetMessage);
            textView.Text = this.Intent.GetStringExtra("Message");
        }
    }
}

実行すると、以下のようになります。

f:id:okazuki:20160819220537p:plain

f:id:okazuki:20160819220547p:plain

画面遷移が行われて、値が渡されていることが確認できます。