Xamarin の FormsGallery を XAML で書き直してみる

Xamarin.Forms のサンプルに FormsGallery があります。Xamarin.Forms で使っているひと通りのコントロールが載っているので、どんなものがあるのか見るのに便利なのです。ただ、中のコードは、C# でひとつひとつのコントロールを作るスタイルになっているので、XAML で作る場合にはどうするのか、いまひとつ解りづらい…ので、コンバートしてみました。

https://github.com/moonmile/XFormsGallery

ところどころ未完成なところがあるのですが、ひとまず1日で出来上がったところまで。
共通プロジェクトは PCL を使っています。XAML を素直に共通化するだけであれば PCL で良いでしょう。WinStore/WinPhone のユニバーサルプロジェクトのようにコードビハイドに手を加える場合には、共有プロジェクトを使うと良いかと。

■注意

現時点の Xamarin.Formsのバージョンは「1.1.1.6206」になっているのですが、Visual Stuido 2013 に含まれているテンプレートでは、「1.0.6186」になっています。ほとんど変わらないですが TableView の概観がちょっと違うので、Xamarin の Sample のように、最新のバージョンに合わせています。プロジェクトごとに NuGet で最新にしてください。

以下、ざっと XAML にするときに手順を書き下しておきます。

■App.cs を書き換える

プロジェクトテンプレートで作ると、PCL プロジェクトの App.cs にページを作るコードがあります。ここをごっそり削って、Page クラスのインスタンスを返します。ただし、サンプルの場合には特殊でナビゲーションを使っています。この場合は特別に NavigationPage のインスタンスを作成します。

1
2
3
4
5
6
7
public class App
{
    public static Page GetMainPage()
    {
        return new NavigationPage(new HomePage());
    }
}

■簡単な LabelDemoPage を作る

ラベルだけが表示されるページはこんな感じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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="XFormsGallery.LabelDemoPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <OnPlatform.iOS>10,20,10,5</OnPlatform.iOS>
            <OnPlatform.Android>10,0,10,5</OnPlatform.Android>
            <OnPlatform.WinPhone>10,0,10,5</OnPlatform.WinPhone>
        </OnPlatform>
    </ContentPage.Padding>
    <StackLayout>
        <Label Text="Label" Font="50" HorizontalOptions="Center"></Label>
        <Label Font="Large" VerticalOptions="CenterAndExpand">
            <Label.Text>Xamarin.Forms is a cross-platform natively backed UI toolkit abstraction that allows developers to easily create user interfaces that can be shared across Android, iOS, and Windows Phone.</Label.Text>
        </Label>
    </StackLayout>                       
</ContentPage>

OnPlatform のところは、OSによってコードを切り替えらるところで、元のサンプルの Device.OnPlatform にあたります。Top だけ切り替えられるような気もするのですが、うまくいかなかったので Thickness まるごと切り替えます。iOS だけ 20 ドット広げてあるのは、iPhone のステータスバー用です。ただし、ナビゲーターの場合は自動でステータスバーに対応しているらしく、これはあまり意味がありません。全画面表示するページを作るときに使う技ですね。

元ネタの LabelDemoPage を見ると、次のようになるので、解りやすいような解りにくいような。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class LabelDemoPage : ContentPage
{
    public LabelDemoPage()
    {
        Label header = new Label
        {
            Text = "Label",
            Font = Font.BoldSystemFontOfSize(50),
            HorizontalOptions = LayoutOptions.Center
        };
 
        Label label = new Label
        {
            Text =
                "Xamarin.Forms is a cross-platform natively " +
                "backed UI toolkit abstraction that allows " +
                "developers to easily create user interfaces " +
                "that can be shared across Android, iOS, and " +
                "Windows Phone.",
 
            Font = Font.SystemFontOfSize(NamedSize.Large),
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
 
        // Accomodate iPhone status bar.
        this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);
 
        // Build the page.
        this.Content = new StackLayout
        {
            Children =
            {
                header,
                label
            }
        };
    }
}

XAML 自体は、Xamarin Studio 上で手書きをします。Visual Studio 上でも書けないことはないのですが、タグのコード補完が効かないので、非常にやりにくいです。本当はデザイナが欲しいところでしょうが、スマートフォンのような小さな画面の場合には自由度が少ないので、ほとんど StackLayout か Grid を使ってしまうのであまり関係ないでしょう。ですが、iPad や Surface のようなタブレットPC のレイアウトをするときにはデザイナは必須ですよね。このあたりは、今後どうするのか不明です。

Windows Phone(SilverLightですが)の XAML に直す時に ConvertPageToUIElement メソッドを呼び出しているので、この逆変換ができれば Visual Studio 上で XAML のデザインができるようになるかもしれません。

■HomePage ページを作る

トップページは、メニュー用のページです。
TableView でリスト表示をしているのですが、この親子関係が解りづらいところです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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="XFormsGallery.HomePage"
                Title="XAML Forms Gallery">
    <TableView Intent="Menu">
        <TableView.Root>
            <TableSection Title="Views for Presentation">
                <TextCell Text="Label" x:Name="cellLabel" ></TextCell>
                <TextCell Text="Image" x:Name="cellImage"></TextCell>
                <TextCell Text="BoxView" x:Name="cellBoxView"></TextCell>
                <TextCell Text="WebView" x:Name="cellWebView"></TextCell>
                <TextCell Text="Map" x:Name="cellMap"></TextCell>
            </TableSection>
            <TableSection Title="Views that Initiate Commands">
                <TextCell Text="Button" x:Name="cellButton" ></TextCell>
                <TextCell Text="SearchBar" x:Name="cellSearchBar"></TextCell>
            </TableSection>
...

ただし、元ネタの HomePage.cs を覗いてみると、TableView <- TableView.Root <- TableRoot <- TableSection <- TextCell <- TextCell の関係が解るので、そのまま書き写しています。XAML では TableRoot を省略しても動作するようです(TableView.Rootのほうは省略できないんですよね。ここは Children にして欲しかった)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
this.Title = "Forms Gallery";
this.Content = new TableView
    {
        Intent = TableIntent.Menu,
        Root = new TableRoot
        {
            new TableSection("Views for Presentation")
            {
                new TextCell
                {
                    Text = "Label",
                    Command = navigateCommand,
                    CommandParameter = typeof(LabelDemoPage)
                },
 
                new TextCell
                {
                    Text = "Image",
                    Command = navigateCommand,
                    CommandParameter = typeof(ImageDemoPage)
                },

タップなどの操作は非常に制限されています。労力を減らすたか、これから実装するのか解りませんが、TextCell の場合は Command パターンで呼び出しをしています。ただし、主要なボタンコントロールなどには Clicked イベントが用意されているので、そのままコードビハイドで書くことができます。


WPFやWinStoreで XAML を手書きしたことがある人ならば、デザイナがなくても大体想像して書けるかなという感じですね。Xamarin.Forms の DTD は無いようなので、親子関係はマニュアル http://iosapi.xamarin.com/?link=N%3aXamarin.Forms を見る必要があるのですが、まあ元ネタを見比べていけば、これも想像で書ける範囲かと思います。

カテゴリー: C#, Xamarin パーマリンク