本サイトからスピンオフした姉妹サイトです。Android2015年4月28日MvvmCrossでiOS/Androidアプリの画面遷移をするための基本的な実装方法を説明する。→MvvmCrossのiOS/Androidアプリ開発では、ViewModelのロジックで画面遷移を行う。今回は、iOS/Android各プラットフォームでの基本的な画面遷移の実装方法を解説する*1。Studioでも同様の手順で、本稿の内容が実現できることは確認している)。プラットフォームごとの画面の扱いについてMvvmCrossではCoreプロジェクトの実装によるViewModelベースの画面遷移をすることができる。1つのViewModelに、1つのUIViewControllerやActivityが対応しているため、ViewModelの遷移はそれぞれiOSではUIViewControllerの遷移であり、AndroidではActivityの遷移となる。MvvmCrossの標準動作では、UIViewControllerはUINavigationControllerの子要素となる。Intentの発行など、プラットフォームごとに扱いは異なるが、MvvmCrossによってその差は吸収されるため、Coreプロジェクトの単一実装で画面制御を実現できる。IMvxViewPresenterインターフェースを実装したクラスによりプラットフォームごとの画面制御が行われている。Stackの管理など、各プラットフォームで詳細に画面遷移をカスタマイズできる*2。MvvmCross標準のプレゼンター実装は、GitHubから確認できる。iOSはMvxTouchViewPresenterクラス、AndroidはMvxAndroidViewPresenterクラスを確認しておくとよい。実装方針MVVM設計では、Viewはできる限り画面表示に専念し、ビジネスロジックやナビゲーションロジックはModelやViewModelで実装することになる。今回は画面遷移をViewModelに実装し、Viewはバインディングのみ実装する。最初に、遷移先となるSecondViewを作成し、FirstViewとSecondViewの間で単純な画面遷移の実装を確認する。次に、遷移元のViewModelから遷移先のViewModelへパラメーターを渡す実装を確認する。それではこの手順でサンプルを作成してみよう。「Tips:MvvmCrossのプロジェクトをセットアップするには?」の手順に従い、MvvmCrossプロジェクトを作成する。ソリューション名は「CrossNavigationSample」と設定する。遷移先となる画面のViewModelを用意する。[ソリューション]ビューからCrossNavigationSample.CoreプロジェクトのViewModelsフォルダーを右クリック-[追加]-[新しいファイル]を選択し、(それにより表示される)[新しいファイル]ダイアログから[General]-[空のクラス]を選択する。名前を「SecondViewModel」と入力し[新規]ボタンをクリックする。作成されたSecondViewModel.csファイルを次のように修正する。_backCommand;}}BackCommandを実装する(SecondViewModel.cs)MvxViewModelクラスのClose()メソッドは、引数に受け取ったViewModelに対応する画面を終了する。1は、SecondViewを閉じて、遷移元の画面へ戻る処理である。これにより、ViewクラスからBackCommandプロパティをバインディングすることで、画面を閉じることができるようになる。次に、FirstViewModelクラスを実装する。CrossNavigationSample.CoreプロジェクトのViewModelsフォルダー内にあるFirstViewModel.csファイルを次のように修正する。_goToSecondCommand;}}画面遷移を実装する(FirstViewModel.cs)1はSecondViewへ遷移する処理である。MvxViewModelクラスのShowViewModel()メソッドは、遷移先となるViewModelの型(=IMvxViewModelインターフェースを継承したクラスの型引数)を受け取り、指定された型のViewModelクラスと、それに対応するViewクラスのインスタンスを生成し、それを表示する。Touchプロジェクトの実装Touchプロジェクトではレイアウトを作成し、バインディングを定義する。今回は.xibファイルを用いてFirstViewとSecondViewのレイアウトを作成する。FirstViewを作成するにはまず、[ソリューション]ビューからCrossNavigationSample.TouchプロジェクトのViewsフォルダーにあるFirstView.csを右クリック-[削除]-削除確認ダイアログの[削除]ボタンをクリックし、ファイルを削除する。Controller]を選択し、名前欄に「FirstView」と設定して[新規]ボタンをクリックする(図1)。Studioのデフォルト設定では関連付いていない)。これには、[設定](Mac)/[オプション](Windows)ダイアログの左側のツリーから[ソースコード]-[.NETの命名ポリシー]を選択し、右側から[名前空間をディレクトリ名に関連付ける]、[既定の名前空間をrootとして使用]というチェックボックスそれぞれにチェックを入れ、[ディレクトリ構造:]欄で[フラット]を選択して[OK]ボタンで保存すればよい。ViewsフォルダーへFirstView.xibファイルおよびFirstView.csファイルが作成され、FirstView.xibをダブルクリックするとXcodeが起動する。Xcodeから図2のようなレイアウトを作成し、GoToSecondButtonの名前でUIButton(=iOS標準のボタン)のアウトレットを作成する*3。念のため、いったんここで保存しておこう。Insider」を参考にされたい)。Xcodeを利用できない環境では、Xibファイルを用いずにC#のコードによってレイアウトを作成しても構わない。FirstView.xibのレイアウトFirstViewと同様の手順でSecondView.xibファイルおよびSecondView.csファイルを作成する。SecondView.xibをダブルクリックし、図3のようにレイアウトを作成する。SecondView.xibのレイアウト次にバインディングを定義する。ViewsフォルダーのFirstView.csを次のように修正する。vm.GoToSecondCommand);set.Apply();}}}バインディングの設定(FirstView.cs)1では、継承元のクラスをMvxViewControllerへ変更していることに注意してほしい。MvxViewControllerクラスは、バインディングに対応したUIViewControllerである。2でバインディングを設定している。Viewクラスの実装はバインディングのみとなる。同様に、ViewsフォルダーのSecondView.csを次のように修正する。vm.BackCommand);set.Apply();}}}バインディングの設定(SecondView.cs)Droidプロジェクトの実装Droidプロジェクトについてもレイアウトを作成し、バインディングを定義する。FirstViewを編集する。[ソリューションビュー]からCrossNavigationSample.DroidプロジェクトのResources-layoutフォルダーにあるFirstView.axmlファイルを次のように編集する。/></LinearLayout>レイアウトの作成(FirstView.axml)次に、同じくlayoutフォルダーを右クリックし、[追加]-[新しいファイル]-[Android]-[Layout]を選択し、名前欄に「SecondView」と設定して[新規]ボタンをクリックする(図4)。SecondView.axmlファイルの作成layoutフォルダーへ作成されたSecondView.axmlファイルを次のように編集する。/></LinearLayout>レイアウトの作成(SecondView.axml)Androidでは、バインディングは.axmlファイルへ定義できるため、クラスファイルの実装は必要最小限のものとなる。CrossNavigationSample.DroidプロジェクトのViewsフォルダーを右クリックし[追加]-[新しいファイル]-[Android]-[Activity]と選択し、「SecondView」と設定して[新規]ボタンをクリックする(図5)。作成されたSecondView.csファイルを次のように編集する。(bundle);SetContentView(Resource.Layout.SecondView);}}}Viewクラスの実装(SecondView.cs)1では継承元クラスをMvxActivityに変更している。MvxActivityはバインディングに対応したActivityである。CrossNavigationSample.Droidプロジェクトに存在しているFirstView.csファイルは修正する必要はない。アプリケーションの実行ここまでで、単純な画面遷移実装が完了した。SecondView]ボタンをタップするとSecondView画面へ遷移する。FirstView]ボタンをタップするとSecondView画面を閉じ、FirstView画面が表示される(図6)。アプリケーションの実行結果パラメーターを用いた画面遷移の実装MvvmCrossのプロジェクトでは、画面は任意のパラメーターを受け取ることができる。これを試すために、SecondViewを文字列と数値の2つのパラメーターを受け取るように拡張し、FirstViewからSecondViewをパラメーター付きで呼び出すように修正してみよう。Coreプロジェクトの修正CrossNavigationSample.CoreプロジェクトのSecondViewModel.csファイルを次のように修正する。_backCommand;}}パラメーター受け取り部分の実装(SecondViewModel.cs)MvvmCrossではInit()という名前のメソッドを定義すると、パラメーターを渡されてViewが起動したときに、その引数が渡された上で、Init()メソッドが実行される。1により、引数となるSecondViewParameterクラスを定義している。SecondViewParameterはstring型のMessageプロパティとint型のNumberプロパティをメンバーとして保持する。2により、SecondViewParameter型のオブジェクトを引数として受け取るInit()メソッドを定義している。これによりSecondViewModelクラスは、そのインスタンス生成時にSecondViewParameterオブジェクトおよび、そのメンバーのMessageとNumberを受け取ることになる。Init()メソッド内では、その引数を3のMessageプロパティへ設定する。3のMessageプロパティは画面表示用であり、Viewからバインディングされる。Init()メソッドは、継承元であるMvxViewModelクラスでは定義されておらず、オーバーライドもしていない。これはMvvmCrossがInit()メソッドをリフレクションによって検出しているためである。そのため、メソッド名のスペルミスには注意する必要がある。次に、CrossNavigationSample.CoreプロジェクトのFirstViewModel.csを以下の通り編集する。_goToSecondCommand;}}パラメーター付き画面呼び出し(FirstViewModel.cs)1ではバインディング用のMessageプロパティを定義している。これはViewからバインディングし、入力プロパティとして用いる。2では引数となるSecondViewParameterクラスのインスタンスを生成し、ShowViewModel()メソッドによりSecondViewへ引数として渡している。Touchプロジェクトの修正CrossNavigationSample.TouchプロジェクトのFirstView.xibファイルをダブルクリックし、Xcodeから図7のようにレイアウトを修正する。新しく追加したUITextFieldクラス(=iOS標準のテキストフィールド)に対してMessageTextという名前でアウトレットを定義する。FirstViewのレイアウト同様にSecondView.xibファイルを図8のようにレイアウトを修正する。新しく追加したUILabelクラス(=iOS標準のラベル)に対してMessageTextという名前でアウトレットを定義する。SecondViewのレイアウトCrossNavigationSample.TouchプロジェクトのFirstView.csファイルを次のように修正する。vm.GoToSecondCommand);set.Apply();}}}MessageTextバインディングの追加(FirstView.cs)同様にSecondView.csファイルを次のように修正する。vm.BackCommand);set.Apply();}}}MessageTextバインディングの追加(SecondView.cs)Droidプロジェクトの修正CrossNavigationSample.DroidプロジェクトのFirstView.axmlファイルを以下のように修正する。ここで追加するEditTextウィジェット(=Android標準のエディットテキスト)は、FirstViewModelクラスのMessageプロパティへバインドしている。/></LinearLayout>EditTextの追加(FirstView.axml)同様に、SecondView.axmlファイルを以下のように修正する。ここで追加するTextViewウィジェット(=Android標準のテキストビュー)はSecondViewModelクラスのMessageプロパティへバインドしている。/></LinearLayout>TextViewの追加(SecondView.axml)アプリケーションの実行ここでアプリケーションを実行すると、それぞれ以下のような画面となる。FirstViewで入力した文字列がSecondViewへパラメーターとして渡されている様子が確認できる(図9)。パラメーターありのアプリケーションの実行結果パラメーターの型について本稿で定義したSecondViewParameterクラスはstring型と、int型のプロパティを定義していた。MvvmCrossではこのViewModelのパラメーターとして用意するクラスは、シリアライズ可能でなくてはならない。具体的には、パラメータークラスのメンバープロパティは次の型に制限される。OSのライフサイクルに従って管理されるが、このActivityがパラメーターとして受け取ることのできるBundleクラスはシリアライズ可能なクラスである。MvvmCrossはAndroidアプリケーションの画面パラメーターを引き渡すときに、このBundleクラスを利用しているため、上記のような型制限の制約を受けている。パラメーター引数の匿名クラス化について本稿ではSecondViewParameterクラスをパラメータークラスとして定義してそれを用いたが、パラメーターとして匿名クラスを受け渡しすることも可能である。匿名クラスを用いると、パラメータークラスを別途定義する手順を省略でき、パラメーターが簡易なものである場合には便利な表記となる。本稿の例では、呼び出しコードとInit()メソッドを次のように実装することで、パラメータークラスを用いた場合と同様の動作となる。匿名クラスのプロパティ名とInit()メソッドの引数名が合致していることに注意してほしい。number;}......省略......匿名クラスを用いたInit()側のコード(SecondViewModel.cs)匿名クラスを用いた簡易実装はクラス定義が不要という簡便さのメリットはあるが、呼び出し側のコードの実装時にコンパイル時の型チェックやスペルミスに気付きにくいというデメリットもあるため注意して利用すること。※以下では、本稿の前後を合わせて5回分(第45回~第49回)のみ表示しています。INDEX]を参照してください。Xamarin.Formsでトリガーを使用するには?イベントやプロパティの変化に応じたコントロールの外観の変更をXAMLだけで実装できるトリガーの基本的な使用方法を解説する。Xamarin.FormsでWebビューを使用するには?外部のWebページやローカルに配置されたHTMLコンテンツを簡単に表示できるWebViewコントロールをXamarin.Formsで使う方法を説明する。MvvmCrossで画面遷移するには?MvvmCrossでiOS/Androidアプリの画面遷移をするための基本的な実装方法を説明する。Xamarin.Formsでプラットフォームごとの微調整を行うには?カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。MvvmCrossでAndroidの画面の再生成に対応するには?Androidアプリでは別アプリ移動時に画面が破棄され、アプリ再表示時に画面が復元される場合がある。この画面の再生成を、MvxViewModelのライフサイクルメソッドにより行う方法を説明する。機械学習エンジニアを目指す人~初中級者のための技術情報サイトです。「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。開発者のためのSlackチーム、作りました:「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。2020最適なビューへの切り替えを推奨します:スマートフォン用表示に。