Xamarin逆引きTips
Xamarin.Formsでプラットフォームごとの微調整を行うには?
カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。
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。
- *2 Device.Stylesについては、Xamarin.Forms ver 1.3.2以前では正常に動作しないことが報告されている。
Device.Styles
クラスの動作を確認するため、(「Tips:「Xamarin.FormsでWebビューを使用するには?」で作成したサンプルの)App.csファイルを以下のように修正した。
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;
}
}
}
|
6個のLabel
コントロールをStackLayout
で縦に並べ、それぞれのText
/Style
プロパティに、Device.Styles
クラスに定義されている6種類のフィールド値(キー名/スタイル)を適用している。
このコードを実行すると、次のような画面になる。
2. Device.GetNamedSize
フォントのサイズを指定するとき、Device.GetNamedSize
メソッドを使用することができる。
Device.GetNamedSize
メソッドの動作を確認するため、App.csファイルを以下のように修正した。
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;
}
}
}
|
NameSize
列挙型を一覧し(1)、Device.GetNamedSize
メソッドを使用して、それぞれのフォントサイズを指定した(2)。
なお、表示は、FontSizeの名称と、実際にセットされたフォントサイズである(3)。
このコードを実行すると、次のような画面になる。
iOSとAndroidを(フォントサイズの数値で)比較したとき、MicroとMediumでは、微妙にサイズが違うのが分かる。また、Defaultの違いから、デバイスごとに、基準となるサイズが違うことが分かる。
3. Device.Idiom
Device.Idiom
は、TargetIdiom
列挙型のプロパティであり、動作しているデバイスによって、下記の4種類の値をとる。
- Desktop
- Phone
- Tablet
- Unsupported
Device.Idiom
プロパティの動作を確認するため、App.csファイルを以下のように修正した。
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
};
}
}
}
|
画面の中央にラベルを配置し(1)、そのテキストにDevice.Idiom
プロパティの値(=デバイスの名前)を表示した(2)。
このコードを実行すると、次のような画面になる。
Device.Idiom
プロパティの値が、iPhoneではPhoneとなり、iPadではTabletになっているのが分かる。
4. Device.OS
Device.OS
プロパティは、TargetPlatform
列挙型であり、動作しているOSによって、次の値をとる。
- Android
- iOS
- WinPhone
- Other
Device.OS
プロパティの動作を確認するため、App.csファイルを以下のように修正した。
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;
}
}
}
|
画面の中央にラベルを配置し(1)、テキストにDevice.OS
プロパティの値(=OSの名前)を表示した(2)。
また、ちょっとトリッキーな例であるが、通常白色のバックとなるiOSで背景色を黒とし(3)、反対に通常黒のAndroidでは白色の背景にしてみた(4)。
このコードを実行すると、次のような画面になる。
5. Device.OnPlatform
Device.OnPlatform
メソッドは、第1パラメーターから順にiOS、Android、Windows Phoneの処理(=Action
デリゲート型の値)という3つのパラメーターをとるメソッドだ。動作しているプラットフォームによって、そのうちの1つの値を返すことで、プラットフォームごとに処理を切り分けることができる。
Device.OnPlatform
メソッドの動作を確認するため、App.csファイルを以下のように修正した。
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
}}
};
}
}
}
|
スタックレイアウトの先頭に赤色のBoxView
を配置しているが(2)、iOSの場合だけ、トップに20
のマージンが入るようにした(1)。
Thickness
メソッドは、左、上、右、下の4つのパラメーターを取るが、そのうちの上の指定にDevice.OnPlatform
メソッドが返す値を使用している。
iOS 7以降、画面の上部いっぱいにレイアウトすると、表示が重なってしまうため、この書式はXamarin.Formsでの定型句とも言える。
このコードを実行すると、次のような画面になる。
6. Device.OpenUri
Device.OpenUri
メソッドは、URLを指定して呼び出すだけで、それぞれのプラットフォームで標準となっているブラウザーを起動させることができる。
Device.OpenUri
メソッドの動作を確認するため、App.csファイルを以下のように修正した。
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
};
}
}
}
|
画面にボタンを配置し(1)、それを押したとき、ブラウザーでXamarin社のWebページを開くようにした(2)。
このコードを実行して、[Open]ボタンを押すと、次のような画面になる。
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で使う方法を説明する。
48. 【現在、表示中】≫ Xamarin.Formsでプラットフォームごとの微調整を行うには?
カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。
49. MvvmCrossでAndroidの画面の再生成に対応するには?
Androidアプリでは別アプリ移動時に画面が破棄され、アプリ再表示時に画面が復元される場合がある。この画面の再生成を、MvxViewModelのライフサイクルメソッドにより行う方法を説明する。
50. Xamarin.Formsでローカルデータベースを使用するには?
アプリを終了して再起動したときに、ユーザーデータを復活させたい場合、ローカルやクラウドにデータを保存することになる。その一つの方法として、SQLite.Netを使ってローカルDBに保存する方法を説明する。