Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.Formsでプラットフォームごとの微調整を行うには?

2015年5月8日

カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。

古谷 誠進(@furuya02
  • このエントリーをはてなブックマークに追加

 Xamarin.Formsでは基本的に、ポータブル・クラス・ライブラリ(PCL)に共通のコードを記述する。そして、プラットフォームごとで違う部分は、カスタムレンダラーやDependencyServiceの仕組みを使用することになる。

 しかし、これらの用法を用いるまでもない、画面の微調整などに関しては、その違いをうまく吸収できるDeviceというクラスが用意されている。今回は、このDeviceクラスのメソッドやプロパティについて解説する。

  • *1 なお本Tipsは、Windows上でVisual Studio 2013を使用してXamarin.Forms開発をすることを前提としている(編集部注: Mac上のXamarin Studioでも同様の手順で、本稿の内容が実現できることは確認している)。使用しているXamarin.Formsのバージョンは、2015年4月23日現在で最新stableの「1.4.2.6355」である。

1. Device.Styles

 Device.Stylesは、6種類の組み込みスタイルクラスとして定義されており、ラベルなどのコントロールのスタイル(=Styleプロパティの値)として利用可能である*2

 Device.Stylesクラスの動作を確認するため、(「Tips:「Xamarin.FormsでWebビューを使用するには?」で作成したサンプルの)App.csファイルを以下のように修正した。

C#
using Xamarin.Forms;

namespace WebViewSample {
  public class App : Application {
    public App() {
      MainPage = new MyPage();
    }
    ……省略……
  }

  class MyPage : ContentPage {
    public MyPage() {

      var layout = new StackLayout {
        Padding = new Thickness(0,Device.OnPlatform(20,0,0),0,0),
      };

      layout.Children.Add(new Label {
        Text = Device.Styles.BodyStyleKey, Style = Device.Styles.BodyStyle
      });

      layout.Children.Add(new Label {
        Text = Device.Styles.CaptionStyleKey, Style = Device.Styles.CaptionStyle
      });

      layout.Children.Add(new Label {
        Text = Device.Styles.ListItemDetailTextStyleKey, Style = Device.Styles.ListItemDetailTextStyle
      });

      layout.Children.Add(new Label {
        Text = Device.Styles.ListItemTextStyleKey, Style = Device.Styles.ListItemTextStyle
      });

      layout.Children.Add(new Label {
        Text = Device.Styles.SubtitleStyleKey, Style = Device.Styles.SubtitleStyle
      });

      layout.Children.Add(new Label {
        Text = Device.Styles.TitleStyleKey, Style = Device.Styles.TitleStyle
      });

      Content = layout;
    }
  }
}
コントロールに設定したStyleの動作を確認するコード(App.cs)

 6個のLabelコントロールをStackLayoutで縦に並べ、それぞれのTextStyleプロパティに、Device.Stylesクラスに定義されている6種類のフィールド値(キー名スタイル)を適用している。

 このコードを実行すると、次のような画面になる。

図1 コントロールに設定したStyleの動作を確認した画面(iOS) 図1 コントロールに設定したStyleの動作を確認した画面(Android)
図1 コントロールに設定したStyleの動作を確認した画面(iOS/Android)

2. Device.GetNamedSize

 フォントのサイズを指定するとき、Device.GetNamedSizeメソッドを使用することができる。

 Device.GetNamedSizeメソッドの動作を確認するため、App.csファイルを以下のように修正した。

C#
using System;
using Xamarin.Forms;

namespace WebViewSample {
  ……省略……

  class MyPage : ContentPage {
    public MyPage() {
      var layout = new StackLayout{
        Padding = new Thickness(20, Device.OnPlatform(20, 0, 0), 0, 0),
      };
      foreach (NamedSize n in Enum.GetValues(typeof(NamedSize))){ // <-1
        var label = new Label();
        label.FontSize = Device.GetNamedSize(n, label); // <-2
        label.Text = string.Format("{0} ({1})", n, label.FontSize); // <-3
        layout.Children.Add(label);
      }
      Content = layout;
    }
  }
}
Device.GetNamedSizeメソッドの動作を確認するコード(App.cs)

 NameSize列挙型を一覧し(1)、Device.GetNamedSizeメソッドを使用して、それぞれのフォントサイズを指定した(2)。

 なお、表示は、FontSizeの名称と、実際にセットされたフォントサイズである(3)。

 このコードを実行すると、次のような画面になる。

図2 Device.GetNamedSizeメソッドの動作を確認した画面(iOS) 図2 Device.GetNamedSizeメソッドの動作を確認した画面(Android)
図2 Device.GetNamedSizeメソッドの動作を確認した画面(iOS/Android)

 iOSとAndroidを(フォントサイズの数値で)比較したとき、MicroMediumでは、微妙にサイズが違うのが分かる。また、Defaultの違いから、デバイスごとに、基準となるサイズが違うことが分かる。

3. Device.Idiom

 Device.Idiomは、TargetIdiom列挙型のプロパティであり、動作しているデバイスによって、下記の4種類の値をとる。

  • Desktop
  • Phone
  • Tablet
  • Unsupported

 Device.Idiomプロパティの動作を確認するため、App.csファイルを以下のように修正した。

C#
using Xamarin.Forms;

namespace WebViewSample {
  ……省略……

  class MyPage : ContentPage {
    public MyPage() {
      Content = new Label { // <-1
        XAlign = TextAlignment.Center,
        YAlign = TextAlignment.Center,
        FontSize = 24,
        Text = Device.Idiom.ToString() // <-2
      };
    }
  }
}
Device.Idiomプロパティの動作を確認するコード(App.cs)

 画面の中央にラベルを配置し(1)、そのテキストにDevice.Idiomプロパティの値(=デバイスの名前)を表示した(2)。

 このコードを実行すると、次のような画面になる。

図3 Device.Idiomプロパティの動作を確認した画面(iPhone) 図3 Device.Idiomプロパティの動作を確認した画面(iPad)
図3 Device.Idiomプロパティの動作を確認した画面(iPhone/iPad)

 Device.Idiomプロパティの値が、iPhoneではPhoneとなり、iPadではTabletになっているのが分かる。

4. Device.OS

 Device.OSプロパティは、TargetPlatform列挙型であり、動作しているOSによって、次の値をとる。

  • Android
  • iOS
  • WinPhone
  • Other

 Device.OSプロパティの動作を確認するため、App.csファイルを以下のように修正した。

C#
using Xamarin.Forms;

namespace WebViewSample {
  ……省略……

  class MyPage : ContentPage {
    public MyPage() {

      var label = new Label{ // <-1
        XAlign = TextAlignment.Center,
        YAlign = TextAlignment.Center,
        Text = Device.OS.ToString() // <-2
      };

      if (Device.OS == TargetPlatform.iOS) { 
        BackgroundColor = Color.Black; // <-3
        label.TextColor = Color.White;
      } else if (Device.OS == TargetPlatform.Android) {
        BackgroundColor = Color.White; // <-4
        label.TextColor = Color.Black;
      }

      Content = label;
    }
  }
}
Device.OSプロパティの動作を確認するコード(App.cs)

 画面の中央にラベルを配置し(1)、テキストにDevice.OSプロパティの値(=OSの名前)を表示した(2)。

 また、ちょっとトリッキーな例であるが、通常白色のバックとなるiOSで背景色を黒とし(3)、反対に通常黒のAndroidでは白色の背景にしてみた(4)。

 このコードを実行すると、次のような画面になる。

図4 Device.OSプロパティの動作を確認した画面(iOS) 図4 Device.OSプロパティの動作を確認した画面(Android)
図4 Device.OSプロパティの動作を確認した画面(iOS/Android)

5. Device.OnPlatform

 Device.OnPlatformメソッドは、第1パラメーターから順にiOS、Android、Windows Phoneの処理(=Actionデリゲート型の値)という3つのパラメーターをとるメソッドだ。動作しているプラットフォームによって、そのうちの1つの値を返すことで、プラットフォームごとに処理を切り分けることができる。

 Device.OnPlatformメソッドの動作を確認するため、App.csファイルを以下のように修正した。

C#
using Xamarin.Forms;

namespace WebViewSample {
    ……省略……

  class MyPage : ContentPage {
    public MyPage() {
      Content = new StackLayout {
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), // <-1
        Children = {new BoxView { // <-2
          Color = Color.Red,
          HeightRequest = 100
        }}
      };
    }
  }
}
Device.OnPlatformメソッドの動作を確認するコード(App.cs)

 スタックレイアウトの先頭に赤色のBoxViewを配置しているが(2)、iOSの場合だけ、トップに20のマージンが入るようにした(1)。

 Thicknessメソッドは、左、上、右、下の4つのパラメーターを取るが、そのうちの上の指定にDevice.OnPlatformメソッドが返す値を使用している。

 iOS 7以降、画面の上部いっぱいにレイアウトすると、表示が重なってしまうため、この書式はXamarin.Formsでの定型句とも言える。

 このコードを実行すると、次のような画面になる。

図5 Device.OnPlatformメソッドの動作を確認した画面(iOS) 図5 Device.OnPlatformメソッドの動作を確認した画面(Android)
図5 Device.OnPlatformメソッドの動作を確認した画面(iOS/Android)

6. Device.OpenUri

 Device.OpenUriメソッドは、URLを指定して呼び出すだけで、それぞれのプラットフォームで標準となっているブラウザーを起動させることができる。

 Device.OpenUriメソッドの動作を確認するため、App.csファイルを以下のように修正した。

C#
using System;
using Xamarin.Forms;

namespace WebViewSample {
  ……省略……

  class MyPage : ContentPage {
    public MyPage() {
      Content = new Button { // <-1
        Text = "Open",
        Command = new Command(() => Device.OpenUri(new Uri("http://xamarin.com/"))) // <-2
      };
    }
  }
}
Device.OpenUriメソッドの動作を確認するコード(App.cs)

 画面にボタンを配置し(1)、それを押したとき、ブラウザーでXamarin社のWebページを開くようにした(2)。

 このコードを実行して、[Open]ボタンを押すと、次のような画面になる。

図6 Device.OpenUriメソッドの動作を確認した画面(iOS) 図6 Device.OpenUriメソッドの動作を確認した画面(Android)
図6 Device.OpenUriメソッドの動作を確認した画面(iOS/Android)

 iOSでは、Safariが、Androidでは、その標準ブラウザーが起動されているのが分かる。

7. まとめ

 今回は、各プラットフォームによる違いを微調整するためのDeviceクラスについて解説した。

 このクラスをうまく利用することで、Xamarin.Formsの最大のメリットであるコードの共通化が、一層楽になるだろう。

 なお、Deviceクラスには、今回紹介したものの他、Device.StartTimerメソッドやDevice.BeginInvokeOnMainThreadメソッドがあるが、この2つについては、画面などの微調整とはやや分野が違うので、次回以降にあらためて解説する。

※以下では、本稿の前後を合わせて5回分(第46回~第50回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

46. Xamarin.FormsでWebビューを使用するには?

外部のWebページやローカルに配置されたHTMLコンテンツを簡単に表示できるWebViewコントロールをXamarin.Formsで使う方法を説明する。

47. MvvmCrossで画面遷移するには?

MvvmCrossでiOS/Androidアプリの画面遷移をするための基本的な実装方法を説明する。

48. 【現在、表示中】≫ Xamarin.Formsでプラットフォームごとの微調整を行うには?

カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。

49. MvvmCrossでAndroidの画面の再生成に対応するには?

Androidアプリでは別アプリ移動時に画面が破棄され、アプリ再表示時に画面が復元される場合がある。この画面の再生成を、MvxViewModelのライフサイクルメソッドにより行う方法を説明する。

50. Xamarin.Formsでローカルデータベースを使用するには?

アプリを終了して再起動したときに、ユーザーデータを復活させたい場合、ローカルやクラウドにデータを保存することになる。その一つの方法として、SQLite.Netを使ってローカルDBに保存する方法を説明する。

イベント情報(メディアスポンサーです)

Azure Central の記事内容の紹介

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • 日本マイクロソフト株式会社
  • グレープシティ株式会社