Xamarin.Formsのサンプルで遊んでみたよ!
Evoleve2016始まりましたね!
どんな発表があるかドキドキですね!
サンプルで遊ぶ
Hello, iOSですとかHello Androidもいいですけど
実際にゴリゴリ動いているのを見るとソースをいじるのが楽しくなりますよね。
今回、Xamarin.FormsのGitHubで提供されている、2つのSampleを組み合わせて遊んでみました。
今回組み合わせたサンプル2つ
xamarin-forms-samples/Navigation/LoginFlow/
xamarin-forms-samples/Navigation/MasterDetailPage/
使用しているサンプル名称を見ていただければわかる通りですが
ログイン画面でログイン→MasterDetailページに遷移
といった単純な構成です。とっかりりとしてはこれぐらいがちょうどいいですね。
※MasterDetailPageの構成なんかは、上記のGitHub内にScreenShotがありますのでご覧くださいませ。
まずはサンプルソースをざっと眺めてみる
LoginFlow
開いて早速エラーが出まくったり、MVVMチックな構成ではなかったりと
気になるところは多々ありますが、サンプルを下敷きに新しく作り直せば問題ありません。
LoginPageCS.cs
LoginPage.xaml
まず上の2つのファイルがその名の通りLoginPageのView部分ですね
C#のコードのみでも構成できますし、XAMLを使用することも可能です。
Sampleを組み合わせるうえでLogInPage側の肝のLogicは下記部分ですね。
(実際には色々基本的な部分で重要な部分はいっぱいありますよ!)
LoginPage.xaml,cs
async void OnLoginButtonClicked (object sender, EventArgs e) { var user = new User { Username = usernameEntry.Text, Password = passwordEntry.Text }; var isValid = AreCredentialsCorrect (user); if (isValid) { App.IsUserLoggedIn = true; Navigation.InsertPageBefore (new MainPage (), this); await Navigation.PopAsync (); } else { messageLabel.Text = "Login failed"; passwordEntry.Text = string.Empty; } }
入力されたユーザー名称とパスワードが一致しますかー?というものを確認。
Navigation.InsertPageBeforeで遷移先のページを生成し、Navigation.PopAsyncでページ遷移を行っています。
今回やりたいのは、このMainPageをMasterPageDetailのSampleで使用されているMain画面にするだけです。
MasterDetailPage
こちらはLogic部分で変更する箇所はありません。
ただ、押さえておきたいのは、下記の内容です。
MainPage.xaml
<?xml version="1.0" encoding="UTF-8"?> <MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation" x:Class="MasterDetailPageNavigation.MainPage"> <MasterDetailPage.Master> <local:MasterPage x:Name="masterPage" /> </MasterDetailPage.Master> <MasterDetailPage.Detail> <NavigationPage> <x:Arguments> <local:ContactsPage /> </x:Arguments> </NavigationPage> </MasterDetailPage.Detail> </MasterDetailPage>
CSのコードハイライトはちと役不足感があるけどまぁいいか
MainPage.xaml.cs
public MainPage () { InitializeComponent (); masterPage.ListView.ItemSelected += OnItemSelected; if (Device.OS == TargetPlatform.Windows) { Master.Icon = "swap.png"; } } void OnItemSelected (object sender, SelectedItemChangedEventArgs e) { var item = e.SelectedItem as MasterPageItem; if (item != null) { Detail = new NavigationPage ((Page)Activator.CreateInstance (item.TargetType)); masterPage.ListView.SelectedItem = null; IsPresented = false; } }
MainPageがMasterとDetailに分かれており、それぞれページが指定されています。
Maseterがわが「MasterPage」Detail側が「ContactsPage」です。
リストアイテムの選択処理はMasterPage(子)のCSではなく、MainPage(親)で行われています。
XAML側7行目で配置された、MasterPageに配置されたListViewのEventをキャッチし、選択処理が行われています。
NavigationPageでページ遷移を行っています。
item.TargetTypeはMainPageやContentPage等のXAMLで作成したページ名称ですね。
では組み合わせてみよう
前述の通り、Sampleをそのままですとエラーが多すぎるため
新しいソリューションを立ち上げて、ソースを組み合わせていきます。
途中過程はすっとばしまして、ソリューションの構成は下記の通りです。
MVVMっぽい構成になりました。
Mock内にはSampleUserをつっこんでます。
ViewModel内には、UserViewModelとMenuのViewModelですね。
Xamarin.Droid,/iOsにはResourceとして、アイコン情報を登録しただけです。
Droidは \Resources\drawableに
iOSは \Resourcesに格納しました。
デバイス側にはコードを1行も記述していないです。スバラシイ
実行
ログインページでた!
が、ログイン処理時にエラー!!
やはりすんなりはいかないか…
エラーの内容を確認すると
「Navigationページは1ページ1個しか認めませんよ!」という内容のようです。
そりゃそうだ。
では、ここでXAMLを見ていきます。
たしかに、MasterDetailを使用しているMainPage.xamlは
しかし、LoginPageには
では、どこにあるのでしょうか。
App.cs
public App() { if (!IsUserLoggedIn) { MainPage = new NavigationPage(new LoginPage()); } else { MainPage = new NavigationPage(new MainPage()); ; } }
App.csでアプリケーション立ち上げ時のページを指定していますが
ここの部分で、LoginPageがNavigationPageとしてNewされています。
だから、ログインアクション時の、「Navigation.InsertPageBefore (new MainPage (), this)」が使用できるわけですね。
対処療法的に対処してみる
変更後のMainPage.xaml
<?xml version="1.0" encoding="UTF-8"?> <MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:XamarinSample.Views;assembly=XamarinSample" x:Class="XamarinSample.Views.MainPage"> <MasterDetailPage.Master> <local:MasterPage x:Name="MasterPage" /> </MasterDetailPage.Master> <MasterDetailPage.Detail> <!--<NavigationPage>--> <!--<x:Arguments>--> <local:ContactsPage /> <!--</x:Arguments>--> <!--</NavigationPage>--> </MasterDetailPage.Detail> </MasterDetailPage>
完全に対処療法ですが
すでにLoginPageからNavigationを使用したページ遷移が行われているわけですし
改めてNavigationPageタグの宣言する必要ないよね?ってことでNavigationタグを消してみました。
まとめ
- Sampleソースは見るのもいじるのも勉強になります。
- いきなり作りたいものを作るより、Sampleを組み合わせるほうがイメージしやすいかも?
次
EmployeeDirectoryのSampleを流用して、ユーザー管理画面を作ってみようかなと考えています。
あぁ、でもBotFrameworkも気になってるんですよね
まぁ、明日から月曜なんで、遊ぶのはしばらくお預けです…。
ものすごい長くなったんで次回は抑えれるよう頑張ります。