vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

Xamarin.Formsに触れてみた話

はじめに

この記事は [初心者さん・学生さん大歓迎!] Xamarin その1 Advent Calendar 2017 - Qiita の一日目の記事です。

qiita.com

なんとなく気になりつつも触れていなかった Xamarin に触れてみた、という内容です。

なお Xamarin には AndroidiOS の薄いラッパーである Xamarin.Android / Xamarin.iOS もありますが、
今回は Xamarin.Forms を試してみることにしました。

理由としては、同じように C# で書けてマルチプラットフォームに対応する Unity との使い分けができると良いな、と思ったためです。

Xamarinプログラミング入門をベースに自分の興味に任せて試した内容をまとめてみたいと思います。

準備

まずは準備から。 Visual Studio は 2017.15.4.4 Community Edition を使っています。

インストールは Visual Studio 本体のインストール時か、メニューの ツール > ツールと機能を取得 から、
.Netによるモバイル開発 にチェックを入れると可能です。

簡単ですね。

Xamarin Live Playerが有効にならない

Xamarin には Xamarin Live Player という機能があり、
AndroidiPhone に同名のアプリをインストールして Visual Studio とリンクしておくと、
同一ネットワークにつながっている場合はUSBケーブルでPCに接続しなくても実機でのデバッグを行うことができます。
(iPhoneMac が必要)

使い方は例えば Android なら、プロジェクトを Android に切り替えて、
バイスを選択するところから Xamarin Live Player を選択・・・

できませんでした/(^o^)\

Visual Studio のバージョンは問題ないし、 Xamarin も最新といっているし・・・

と思っていたら、公式サイトに載っていました。

どうやらデフォルトでは有効になっていないらしく、
ツール > オプション > Xamarin > その他 から、 Xamarin Live Playerを有効にする にチェックを入れる必要があるそうです。

f:id:mslGt:20171130233638j:plain

f:id:mslGt:20171130233822j:plain

ちゃんと説明は読みましょう、というお話でしたorz

なお有効にしたあと、テザリング環境でも試してみましたが、
Androidについてはテザリング環境でも問題なく接続できました。

確認したい端末が複数台ある場合など、結構便利なのではないでしょうか。

デフォルトのプロジェクトを見てみる

テンプレートを Blank App 、 Code Sharing Strategy を PCL にして Xamarin プロジェクトを作成すると、
以下の4つのプロジェクトを持つソリューションが生成されます。
(プロジェクト名は XamarinSample としました)

  • XamarinSample (移植可能)
  • XamarinSample.Android
  • XamarinSample.iOS
  • XamarinSample.UWP

View は XamarinSample (移植可能) のものを使います。

が、ほかのプロジェクトを見てみると、それぞれ MainPage.xaml(UWP) や MainActivity.cs(Android) など、
スタートアップやメインページの表示に関わりそうなファイルが見つかります。

とりわけ気になったのが UWP 。
MainPage.xaml と App.xaml って、 XamarinSample (移植可能) と一緒じゃないのという。

試しに UWP の MainPage.xaml にボタンなどを追加してみましたが、
少なくともデフォルトでは反映されませんでした。

また、 MainPage.xaml を削除するとエラーが発生しました。

基本的に各プロジェクトのコードはスタートアップのために存在するもののようで、
UWP については MainPage.xaml.cs や App.xaml.cs のコードビハインドが必要なので空の Xaml ファイルがある、
ということのようです。

xamlxaml.csについて

XamarinSample (移植可能) の MainPage.xaml と MainPage.xaml.cs ですが、
デフォルトではプロジェクト直下にあります。

これを View というディレクトリを作ってその中に移動し、
MainPage.xaml.cs の namespace を合わせて XamarinSample.View のように変更してやると、エラーになります。

これは MainPage.xaml や App.xaml.cs で MainPageクラスを呼んでいるためで、
合わせて変更してあげる必要があります。

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="XamarinSample.View.MainPage"> 
~省略~
< /ContentPage>

App.xaml.cs

~省略~
public App()
{
    InitializeComponent();
    MainPage = new XamarinSample.View.MainPage(); 
}
~省略~

イベントとナビゲーションの追加

それでは、画面にボタンを追加して別のページに遷移する、というのを試してみたいと思います。

まずは SubPageOne.xaml というページを追加しておきます。

ナビゲーション

Xamarin.Forms では、 NavigationPage を使用することで、
比較的簡単にページ遷移が実装できるようになります。

NavigationPage を使用するためには、
XamarinSample (移植可能) の App.xaml.cs を変更する必要があります。

Before

~省略~
public App()
{
    InitializeComponent();
    MainPage = new XamarinSample.View.MainPage();
}
~省略~

After

~省略~
public App()
{
    InitializeComponent();
    MainPage = new NavigationPage(new XamarinSample.View.MainPage());
}
~省略~

あとは下記のように Navigation.PushAsync を使えばOKです。 (なお遷移後のページには戻るボタンが自動で表示されます)

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XamarinSample.View
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
        async void OpenSubPageOneButtonClicked(object sender, EventArgs e)
        {
            // 遷移後のページ(SubPageOne.xaml.cs を指定する).
            await Navigation.PushAsync(new SubPageOne());
        }
    }
}

遷移前

f:id:mslGt:20171130234051j:plain

遷移後

f:id:mslGt:20171130234115j:plain

イベント

MainPage.xaml にボタンを追加して、 MainPage.xaml.cs の OpenSubPageOneButtonClicked をイベント関数としてセットします。

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="XamarinSample.View.MainPage">
    < ContentPage.Content>
        < AbsoluteLayout BackgroundColor="Yellow">
            < Button AbsoluteLayout.LayoutBounds="20,20,200,30" Clicked="OpenSubPageOneButtonClicked" BackgroundColor="#0078d7">SubPage1< /Button>
        < /AbsoluteLayout>
    < /ContentPage.Content>
< /ContentPage>

プラットフォーム固有のクラスを呼ぶ

さて、基本的には各プラットフォーム共通の処理を XamarinSample (移植可能) に追加していくわけですが、
中にはプラットフォームごとに処理を分ける必要がある場合もあります。

その場合の方法はいくつかあるようですが、
今回は DependencyService を使うことにしました。

XamarinSample (移植可能) にインターフェースを作っておき、
各プラットフォームのプロジェクトにそのインターフェースを継承したクラスを作り、
そこで固有の処理を書きます。

で、それを DependencyService を使って実行時に該当プラットフォームのクラスを呼ぶ、
という流れのようです。

ICalc.cs

namespace XamarinSample
{
    public interface ICalc
    {
        float Calc(float currentValue, float calcValue);
    }
}

呼ばれる側

Subtraction.cs (Androidプロジェクトに作成)

using Xamarin.Forms;
using XamarinSample.Droid;

// DependencyServiceで呼べるようにする.
[assembly: Dependency(typeof(Subtraction))]
namespace XamarinSample.Droid
{
    public class Subtraction : ICalc
    {
        public float Calc(float currentValue, float calcValue)
        {
            return 4;
        }
    }
}

Subtraction.cs (UWPプロジェクトに作成)

using Xamarin.Forms;
using XamarinSample.UWP;

// DependencyServiceで呼べるようにする.
[assembly: Dependency(typeof(Subtraction))]
namespace XamarinSample.UWP
{
    public class Subtraction : ICalc
    {
        public float Calc(float currentValue, float calcValue)
        {
            return 2;
        }
    }
}

呼び出す側

SubPageOne.xaml.cs

using System.Diagnostics;
using Xamarin.Forms;
using XamarinSample.ViewModel;

namespace XamarinSample.View
{
    public partial class SubPageOne : ContentPage
    {
        public SubPageOne()
        {
            InitializeComponent();
            var subtraction = DependencyService.Get();
            Debug.WriteLine(subtraction.Calc(0, 1).ToString());
        }
    }
}

これで、Android で実行した場合は 4 が、Windows で実行した場合は 2 が返ってきます。 #if ~ で切り分けるよりシンプルで良いですね。

出力する

apk ファイル (Android) や ipa ファイルとしてアプリを書き出したい場合、 ソリューションエクスプローラーのそれぞれのプロジェクト上で 右クリック -> アーカイブ をクリックすればOKのようです。

UWP は HockeyApp または ストア > アプリパッケージの作成 から。
また WindowsiOS を出力する場合は、 MacXcode に接続されている必要があります。

なおストア配信時の設定は下記のような情報を参考に。

おわりに

同じように C# でコードを書き、マルチプラットフォームにアプリを作成できる Unity とはずいぶん違うのだなぁ、というのが率直な感想です。

C#7が使えたり (Unity は Experimental な機能を On にしても C#6 までの対応 )、
独自のお作法ももちろんあるのでしょうが、 WPF など普通の? C# に近い印象を受けました。

もちろん Unity が悪いって話ではなく、ただ違うという話ですよ。念のため。

Xamarin.Forms の XamlGUI エディタがない(っぽい)、
何かいじるとエラーが (大抵実行には問題がなく、エラーの出たプロジェクトをクリーン・リビルドすると直るのですが)、
とまだ発展途上なところも見受けられます。

が、すぐ改善されるだろうと思いますし、できれば自分もそれに寄与できればなぁ、とも思いました。

最後に、今回作ったサンプルは、(ボタン位置などめちゃくちゃですが)黄色をベースに作っていました。

その理由は。。。

♪ We all live in a yellow Xamarin, yellow Xamarin, yellow Xamarin ♫

https://www.youtube.com/watch?v=vefJAtG-ZKI

・・・おあとがよろしいようで。

明日は gnk263 さんです。よろしくお願いいたします(..)_

参照