放浪軍師のXamarin.Formsアプリ開発局

Xamarin.Forms+Prism+ReactivePropertyで素人がAndroidやUWPのアプリを右往左往しながら開発している様を発信していきます。性質上間違いも多いのでご注意ください。

乱ちゃんProjectその1(画面作成)

放浪軍師のXamarin.Formsによるアプリ開発

今日からついにコードをいじりますよ!

まず、初めて訪問された方は以下をお読みください。

www.gunshi.info

 

画面を作る

まずは画面を作ってみたいと思います。

最初に作りたいのはコレ。進言ランダムです。

f:id:roamschemer:20180202002312g:plain

画面の大半は四角のラベルで、下あたりに横長のボタン。

ボタンを押すと数字がランダムで表示。

形としては非常にシンプルですね。

 

画面を構成するのはViewのお仕事なので、MainPage.xamlを改造していきます。

Xamarin.Nativeであれば画面を作るためのツールみたいなのを組み合わせて作れるのですが、Xamarin.Formsでは自力で書くしかありません。

そのうちサポートされたりするんですかね?

 

 [Views.MainPage.xaml]

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloXamarin.Views.MainPage"
             Title="乱屍用乱ちゃんアプリ">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="5*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>

        <Label Text = "1" 
               Grid.Column="0" Grid.Row="0" 
               FontSize = "300" 
               VerticalOptions="FillAndExpand" 
               HorizontalTextAlignment = "Center" 
               VerticalTextAlignment = "Center" 
               FontAttributes = "Bold" />
        <Button Text = "進言ランダム"
                Grid.Column="0" Grid.Row="1" />

    </Grid>
    
</ContentPage>

 出来た画面はこんな感じ。左がUWPで右がAndroidです。

f:id:roamschemer:20180310002313j:plain f:id:roamschemer:20180310002322p:plain

 

んー、まぁかろうじて出来たって感じです。

最初は<StackLayout>というXamarinにおける標準的(?)な並び方を使ってみたんですが、他の画面の事を考えて格子状に出来る<Grid>を使って書いてみました。

しかし真ん中の数字…これは問題がありますね。

自分のスマホに合わせて FontSize = "300" ってしたけれど、これって機種によって見え方変わる気がする。実際UWPとは見え方がちょっと違うし…比率で入力したり出来るのだろうか?それとも既に比率?

調べてみたがまだよくわからないですね。ま、調べてもわからないことはとりあえず置いておきましょう。いつかわかる日が来るさ…

 

ボタンを挙動させる

さて、次はボタンで挙動させてみます。

この画面は、

【ボタンを押す】→【数値が動く】→【数値が止まる】

という挙動をする必要があり、MVVMのルールに従えば、変動するこの数値部分とボタンはViewModelとデータバインディングで繋がなければなりません。

とすると、こんな感じかな?

 

 [Views.MainPage.xaml]

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloXamarin.Views.MainPage"
             Title="乱屍用乱ちゃんアプリ">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="5*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>

        <Label Text = "{Binding SingenLabel}" 
               Grid.Column="0" Grid.Row="0" 
               FontSize = "300" 
               VerticalOptions="FillAndExpand" 
               HorizontalTextAlignment = "Center" 
               VerticalTextAlignment = "Center" 
               FontAttributes = "Bold" />
        <Button Text = "進言ランダム"
                Command="{Binding SingenRundumCommand}"
                Grid.Column="0" Grid.Row="1" />

    </Grid>
    
</ContentPage>

 ラベルはText = "{Binding SingenLabel}" として、データバインディングができるようにしました。ボタンはCommand="{Binding SingenRundumCommand}"と付け加えて、ボタンとして挙動できるようにしています。

次にViewModelを改造します。

 

[ViewModels.ViewModelBase.cs]

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloXamarin.ViewModels
{
    public class ViewModelBase : BindableBase, INavigationAware, IDestructible
    {
        protected INavigationService NavigationService { get; private set; }

        //進言コマンドラベル
        private string singenLabel;
        public string SingenLabel
        {
            get { return singenLabel; }
            set { SetProperty(ref singenLabel, value); }
        }
        
        //進言コマンドボタン
        public DelegateCommand SingenRundumCommand { get; set; }

        public ViewModelBase(INavigationService navigationService)
        {
            NavigationService = navigationService;
        }

        public virtual void OnNavigatedFrom(NavigationParameters parameters)
        {
            
        }

        public virtual void OnNavigatedTo(NavigationParameters parameters)
        {
            
        }

        public virtual void OnNavigatingTo(NavigationParameters parameters)
        {
            
        }

        public virtual void Destroy()
        {
            
        }
    }
}

進言コマンドを表示するラベル用のプロパティと、ボタン挙動用のプロパティの記述を追加しました。

ボタンはDelegateCommand 型ですね。今後お世話になりそうですヨロシク。

 

[ViewModels.MainPageViewModel.cs]

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HelloXamarin.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        public MainPageViewModel(INavigationService navigationService) 
            : base (navigationService)
        {
            //進言コマンドボタンが押された際に何をする?
            SingenRundumCommand = new DelegateCommand(RundumCommandGet);
        }

        /// <summary>
        /// 進言コマンドを取得する
        /// </summary>
        private void RundumCommandGet()
        {
            SingenLabel = "1";
        }
    }
}

ここには、進言コマンドが押されたらRundumCommandGetを実行しなさいという記述と、そのRundumCommandGetの内容を記述しています。とりあえずボタンを押したらSingenLabel = "1"となるのでラベルに1が表示されるはずです。

 

では実際に動かしてみます。UWPです。

f:id:roamschemer:20180310004359g:plain

おー、ボタンを押すと1が表示されるようになりました。やったぜ!
MVVMにもちゃんと従っていると思いますがどうですかね?

 

さて、あとはこの数字をランダムで取得したりしなければならないのですが、ここまで作るだけで物凄い時間がかかったので今日はこれまで。

やっぱ難しいね!正直動いたのも奇跡だからね!

でもなんだか行けそうな気がする!