Xamarin.Forms VisualStateManager Support
Xamarin.Forms 3.0.0からVisualStateManager、およびVisualStateが追加されます。
VisualStateManager.GoToState()
を呼ぶと対応するVisualStateのSetterが適用される機能です。
これにより、Viewの状態に対応する見た目を宣言的に扱うことが可能となります。
基本的な使い方
基本的な使い方を見てみましょう。入力された文字数に応じてEntryの背景色を変える、新規パスワード入力欄風のサンプルです。
<?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="VisualStateManagerSample.BasicSample"> <StackLayout VerticalOptions="Center" Padding="20"> <Label Text="enter new password" /> <Entry x:Name="_entry" IsPassword="true"> <VisualStateManager.VisualStateGroups> <VisualStateGroupList> <VisualStateGroup x:Name="LengthStates"> <VisualState x:Name="None" /> <VisualState x:Name="Short"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="Red" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Medium"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="Yellow" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Long"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="Green" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateGroupList> </VisualStateManager.VisualStateGroups> </Entry> </StackLayout> </ContentPage>
VisualStateManager.VisualStateGroups
AttachedPropertyを通じてVisualState
をセットします。
VisualStateGroups
はStyleからセットすることが可能なので、VisualStateを含めてViewの規定のスタイルを作ることができます。
using System; using System.Collections.Generic; using Xamarin.Forms; namespace VisualStateManagerSample { [Xamarin.Forms.Xaml.XamlCompilation(Xamarin.Forms.Xaml.XamlCompilationOptions.Compile)] public partial class BasicSample : ContentPage { public BasicSample() { InitializeComponent(); VisualStateManager.GoToState(_entry, "None"); _entry.TextChanged += (s, e) => { if (string.IsNullOrEmpty(_entry.Text)) { VisualStateManager.GoToState(_entry, "None"); return; } var length = _entry.Text.Length; if (length <= 4) { VisualStateManager.GoToState(_entry, "Short"); return; } if (4 < length && length < 8) { VisualStateManager.GoToState(_entry, "Medium"); return; } if (length >= 8) { VisualStateManager.GoToState(_entry, "Long"); return; } }; } } }
コードビハインドではEntryのテキストが更新されるたびに、VisualStateManager.GoToState()
で長さに応じたVisualStateに遷移しています。
同じViusalStateに遷移した場合はSetter適用がスキップされるため、パフォーマンスを気にして厳密に管理する必要はありません。
このサンプル実行結果はこんな感じ。
VisualStateGroup
VisualState
はVisualStateGroup
にまとめられた中で排他的に遷移します。
<VisualStateGroupList> <VisualStateGroup x:Name="Gourp1"> <VisualState x:Name="On" /> <VisualState x:Name="Off" /> </VisualStateGroup> <VisualStateGroup x:Name="Gourp2"> <VisualState x:Name="None" /> <VisualState x:Name="Hightlited" /> </VisualStateGroup> </VisualStateGroupList>
上のようにVisualStateが設定されたViewに対して次の順にGoToSatateを実行した場合...
VisualStateManager.GoToState(view, "On")
VisualStateManager.GoToState(view, "Highlited")
VisualStateManager.GoToState(view, "Off")
結果は次のようになります。
VisualStateManager.GoToState(view, "On")
- Group1/OnのSetterが適用される。
- Group2のSetterは何も適用されない。
VisualStateManager.GoToState(view, "Highlited")
- Group2/HightlitedのSetterが適用される。
- Group1/OnのSetterは解除されない。
VisualStateManager.GoToState(view, "Off")
- Group1/OnのSetterが解除される。
- Group1/OffのSetterが適用される。
- Group2/HightlitedのSetterは解除されず、適用されたまま。
「Setterが適用されていない初期状態に戻す」ということがしたい場合は、Setterを持たないVisualStateを用意しておくと良いです。
Style、Trigger、VisualStateの比較
Xamarin.FormsにはSetter
クラスの集まりによってVisualElementのプロパティを方法として、Style
やTrigger
が以前から存在します。
これらとVisualStateにはどのような違いがあるでしょう。
(便宜上Setter
の塊をカタカナ表記でスタイル呼ぶことにします)
Style
- 特定のクラスに対して規定のスタイルを設定できる。
- 他のStyleを引き継ぐことができる。(
BasedOn
)
Trigger
- イベントの発火やプロパティの変化を契機にVisualElementのプロパティをセットする。
- EnterActoins、ExitActionsを実行できる。
VisualState
- プロパティの設定値をVisualStateという纏まった単位で管理できる。
- VisualStateを変更する判定処理とVisualStateによって変更されるスタイルが分離できる。
状態遷移の判定処理とスタイルの分離がVisualStateの大きな特徴と言えるでしょう。
例えば独自のViewを定義する場合、取りうるVisualStateの名前と条件を公開しておけば、利用者は自分のアプリに合ったスタイルを自由に設定することができます。
規定のVisualState
実は、全てのViewは暗黙的にNomal
、Disabled
、Focused
の3つのVisualStateに遷移します。
それぞれのVisualStateへ遷移するタイミングは以下の通り。
- Nomal
VisualStateManager.VisualStateGroups
AttachedPropertyが更新されたとき。- Viewの
IsEnabled
プロパティがtrueに変更されたとき。 - Viewの
IsFocused
プロパティがfalseに変更されたとき。
- Disabled
- Viewの
IsEnabled
プロパティがfalseに変更されたとき。
- Viewの
- Focused
- Viewの
IsFocused
プロパティがtrueに変更されたとき。
- Viewの
(フォーカス中にIsEnabled = false
したらマズいような……、最終的にDisabledになるのかNormalになるのか、Rendereの実装に依存する?)
本当にVisualStateが変更されているか確かめてみしょう。
こんな感じのXAMLを書きます、自分ではVisualStateManager.GoToState()
しません。
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:VisualStateManagerSample" x:Class="VisualStateManagerSample.CommonStatesSamplePage"> <ContentPage.Resources> <!-- Normal <-> Disabled 確認用 for Image --> <Style TargetType="Image" x:Key="StatusIconStyle"> <Setter Property="VisualStateManager.VisualStateGroups"> <VisualStateGroupList> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <VisualState.Setters> <Setter Property="Source" Value="{local:ImageResource VisualStateManagerSample.Images.online.png}"/> </VisualState.Setters> </VisualState> <VisualState x:Name="Disabled"> <VisualState.Setters> <Setter Property="Source" Value="{local:ImageResource VisualStateManagerSample.Images.offline.png}"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateGroupList> </Setter> </Style> <!-- Normal <-> Disabled 確認用 for Label --> <Style TargetType="Label" x:Key="StatusCaptionStyle"> <Setter Property="VisualStateManager.VisualStateGroups"> <VisualStateGroupList> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <VisualState.Setters> <Setter Property="TextColor" Value="Green"/> </VisualState.Setters> </VisualState> <VisualState x:Name="Disabled"> <VisualState.Setters> <Setter Property="TextColor" Value="Gray"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateGroupList> </Setter> </Style> <!-- Normal <-> Focused 確認用 for Entry --> <Style TargetType="Entry" x:Key="EntryStyle"> <Setter Property="VisualStateManager.VisualStateGroups"> <VisualStateGroupList> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="Green" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Focused"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="Orange" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateGroupList> </Setter> </Style> </ContentPage.Resources> <StackLayout Padding="20" Spacing="30"> <Label Text="CommonStates Sample" /> <!-- SwitchでImageとLabelのIsEnabledを切り替える --> <Grid ColumnSpacing="20"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Style="{DynamicResource StatusIconStyle}" HeightRequest="60" WidthRequest="60" IsEnabled="{Binding IsToggled, Source={x:Reference _onlineSwitch}}" /> <Label Grid.Row="0" Grid.Column="1" Style="{DynamicResource StatusCaptionStyle}" Text="@ticktackmobile" VerticalTextAlignment="End" IsEnabled="{Binding IsToggled, Source={x:Reference _onlineSwitch}}" /> <Switch x:Name="_onlineSwitch" Grid.Row="1" Grid.Column="1" IsToggled="true" /> </Grid> <Entry x:Name="_entry" Style="{DynamicResource EntryStyle}" Placeholder="IsFocused: true = Orange, false = Green" /> </StackLayout> </ContentPage>
local:ImageResource
はEmbeddedResourceから画像を読み込む
ためのXAMLマークアップ拡張です。(Guideに載ってるやつ)
実行結果がこちら。
Xamarin.FormsのVisualStateManagerで規定のVisualStateを確認するサンプル。 pic.twitter.com/ZJ6saTlTp8
— ざまりん.ふぉーむずマン🚲 (@ticktackmobile) March 22, 2018
Xamarin.Forms 3.0.0-pre2ではバグでIsFocusedを変更したときのVisualStateが逆になってます。(修正取り込み済み)
意図しないVisualStateの遷移を防ぐためNomal
、Disabled
、Focused
を使用しないのが無難ですかねー。
Xamarin.Formsにコントリビュートしよう
先日、Xamarin.FormsのVisualSateManagerの解説を書いている途中で、バグを見つけて修正PRを投げました。 せっかくなのでどんな感じだったのか共有します。レッツ貢献!
Xamarin.FormsのVisualStateManagerで規定のVisualStateを確認するサンプル。 pic.twitter.com/ZJ6saTlTp8
— ざまりん.ふぉーむずのソースコード読むマン🚲 (@ticktackmobile) March 22, 2018
「Entryの色が逆じゃね?」と思ったアナタ、鋭い!!Xamarin.Formsのバグです!
— ざまりん.ふぉーむずのソースコード読むマン🚲 (@ticktackmobile) March 22, 2018
この件。
概要
- バグを見つける
- ソースコードの問題個所を確認する
- Reproductionを用意する
- Issueを登録する
- Pull Requestする
- 自動テストがコケる
- 取り込まれる
バグを見つける
Xamarin.Forms 3.0.0-pre2を使って、暗黙的に変化するVisualStateのサンプルコードを書いていたところVisualElement.IsFocused
が変化したときの挙動がおかしい事に気づきました。
ソースコードの問題個所を確認する
条件演算時が逆になってます。修正も簡単なのでバグ報告と一緒に修正PRも投げることにしました。
// 実際のコード VisualStateManager.GoToState(element, isFocused ? VisualStateManager.CommonStates.Normal : VisualStateManager.CommonStates.Focused); // 正しくはこう //VisualStateManager.GoToState(element, isFocused // ? VisualStateManager.CommonStates.Focused // : VisualStateManager.CommonStates.Normal);
Reproductionを用意する
バグ報告にあたってReproduction、つまり最小の再現環境を用意します。 バグ報告者、Reproductionは義務です。え、Reproductionが無い?ZAPZAPZAP!次のバグ報告者はきっとうまくやってくれるでしょう。
もともとサンプルコードを書いていたところだったので、関係ないところを削ってGitHub置いておきます。
Issueを登録する
Xamarin.FormsのリポジトリにはIsuue登録のテンプレートがあります。
### Description 説明を書きます。 ### Steps to Reproduce 再現手順を書きます。 1. 2. 3. ### Expected Behavior 期待する動作を書きます。 ### Actual Behavior 実際の動作(バグ挙動)を書きます。 ### Basic Information バグが発生する環境のバージョンなどを書きます。関係ないのは削ってもOK。 - Version with issue: - Last known good version: - IDE: - Platform Target Frameworks: - iOS: - Android: - UWP: - Android Support Library Version: - Nuget Packages: - Affected Devices: ### Screenshots 見た目に関する問題の場合はスクリーンショットがあると良い。 ### Reproduction Link 最小の再現環境へのリンクを張ります。
実際に登録したIssueがコチラ
バグが報告されると中の人がTriageというGitHubのProjectsに乗せて行程管理するみたい。 「Ready For Work」にあるやつは修正PR受付中かな?
Pull Requestする
Pull Requestにもテンプレートがあります。
### Description of Change ### 変更内容の説明を書きます。 ### Bugs Fixed ### 修正するIssueの番号を書きます。 ### API Changes ### Publicなクラスやメソッドが増えたり減ったりシグネチャが変わったりする場合は列挙します。何も無い場合はNoneで。 ### Behavioral Changes ### 挙動が変わる場合は列挙します。何も無い場合はNoneで。 ### PR Checklist ### PRするときにやることリスト。 - [ ] Has tests (if omitted, state reason in description) - [ ] Rebased on top of master at time of PR - [ ] Changes adhere to coding standard - [ ] Consolidate commits as makes sense
(「Checklistは自己申告なのか?」とか「あからさまにbool逆だっただけなのにテストいるのか?」と悩んだ結果、とりあえず未チェックのままPRしたら結局そのままマージされてしまった。)
実際のPull Requestがコチラ
master
リポジトリ充てにPRしたところ、リリース用ブランチ(3.0.0
)宛てに変えてくれと言われる。分岐点までresetしてから3.0.0
ブランチの先頭にrebaseし、GitHubの機能で宛先を3.0.0
ブランチに変更。
自動テストがコケる
気が付いたら自動ビルドが走っていて(中の人が手動でキックするっぽい?)、数十分後に自動テストが走っていました。 次の日、「UITestxxxxが失敗した」とコメントがついてました。
取り込まれる
件のUITestを確認すると私の修正とは関係なく(そりゃそうだ)、typo修正が不完全でAutomatonId不一致で失敗しているだけでした。 その旨を返答すると数時間後にマージされました。(見返すと英文間違っててヤバイ)
反省
- 一行程度の修正でも横着せずにブランチを切る。
- rebaseが面倒になった。
- CheckListは自分でチェックしていい。
- 雰囲気英文は見直す。
おまけ
- CONTRIBUTING.md
- バグ報告・修正、機能改善提案の仕方
- A Beginner's Guide for Contributing to Xamarin.Forms | Xamarin Blog
- バグ修正の仕方、UITestの追加方法も書かれている。Bugzilla前提であるもののIssueTrackerをGitHubに置き換えればIssueからに対しても同様なはず。
Xamarin.Forms CSS Support
Xamarin.Forms 3.0からCSS Supportが追加されます。(ASP .NET辺りの人たちにリーチしていく狙いらしい?)
一部制限はあるものの大体の機能がそのまま使えるようです、よってこの記事ではXamarin.Forms固有の事情を中心に説明します。 詳しく知りたい人は元のPull Requestを読んでください。
セレクタ関係
要素の指定
CSSにおけるHTML要素名の指定はC#クラス名の指定に置き換えられます。大文字小文字は無視されます。
/* CSS */ boxview { background-color: pink; }
BoxView
クラスの背景色がピンクになります。
StyleClass
CSSにおけるclass属性にはStyleClass
プロパティが対応します。(代わりにclass
プロパティでも良いです)
/* CSS */ .centerelement { background-color: red; }
<!-- XAML --> <StackLayout> <BoxView /> <BoxView StyleClass="centerelement" /> <BoxView /> </StackLayout>
StyleId
CSSにおけるid属性にはStyleId
プロパティが対応します。
/* CSS */ #speciallabel { height: 100; width: 100; background-color: blue; }
<!-- XAML --> <Label Text="I'm special!" StyleId="speciallabel" />
Xamarin.Forms固有のセレクタ
要素名(C#クラス名)の先頭に^
を付けるとそのクラス、およびその派生クラスへの指定となります。
/* CSS */ ^contentpage { padding: 20; background-color: orange; }
この場合、ContentPage
クラスとその派生クラスへの指定となります。通常Xamarin.Formsの各画面はContentPageの派生クラスとして作るため、このようにすれば汎用的なスタイルしてができます。
スタイルシートの読み込み方
XAML
ResourcesプロパティにStyleSheet要素を追加すると、そのViewと子要素にスタイルシートが適用されます。
<ContentPage x:Class="CssSample.CssSamplePage"> <ContentPage.Resources> <StyleSheet Source="/CSS/style.css" /> </ContentPage.Resources> </ContentPage>
ファイルからスタイルシートを読み込む場合、StyleSheet要素のSourceにCSSファイルのパスを記述します。このCSSファイルはEmbeddedResourceにする必要があります。
Sourceに指定するUriにはそのコントロールからの相対パス、または/
で始まるプロジェクトルートからの絶対パスが使用できます。
この画像の場合では../CSS/style.css
または/CSS/style.css
が有効となります。
<ContentPage x:Class="CssSample.CssSamplePage"> <ContentPage.Resources> <StyleSheet> <![CDATA[ ^contentpage { padding: 20; background-color: orange; } stacklayout > boxview { margin: 3; background-color: pink; } ]]> </StyleSheet> </ContentPage.Resources> </ContentPage>
CDATAセクションを使ってXAML内に記述することもできます。
C#
Xamarin.Forms.StyleSheets.StyleSheet.FromAssemblyResource()
を使うとEmbeddedResourceからCSSファイルを読み込めます。
StyleSheet styleSheet = StyleSheet.FromAssemblyResource(this.GetType().GetTypeInfo().Assembly, "CssSample.CSS.style.css"); Resources.Add(styleSheet);
StyleSheet.FromReader()
でTextReaderから読み込むことも可能。
using (var reader = new StringReader(cssString)) myPage.Resources.Add(StyleSheet.FromReader(reader));
CSSとFlexLayout
以前に紹介したFlexLayoutを使うとCSSでもレイアウト指定ができます。
/* CSS */ .section-title { color: #778; font-style: bold; font-size: 20; margin: 6 0 0 6; } .grid { flex-wrap: wrap; flex-direction: row; align-items: stretch; height: 180; } .grid-cell { flex-grow: 0; background-color: #eed; text-align: center; font-size: small; color: #556; } .full { flex-basis: 100%; } .half { flex-basis: 50%; background-color: cornflowerblue; } .third { flex-basis: 33.33%; background-color: pink; } .fourth { flex-basis: 25%; background-color: lightblue; } .auto { flex-grow: 1; background-color: coral; }
<!-- 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="CssSample.FlexCssSamplePage"> <ContentPage.Resources> <StyleSheet Source="../CSS/flexstyle.css" /> </ContentPage.Resources> <ScrollView> <StackLayout> <Label Text="Basic Grids" StyleClass="section-title" /> <FlexLayout StyleClass="grid"> <Label StyleClass="grid-cell, full" Text="full" /> <Label StyleClass="grid-cell, half" Text="1/2" /> <Label StyleClass="grid-cell, half" Text="1/2" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, half" Text="1/2" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, third" Text="1/3" /> <Label StyleClass="grid-cell, third" Text="1/3" /> <Label StyleClass="grid-cell, third" Text="1/3" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, fourth" Text="1/4" /> <Label StyleClass="grid-cell, third" Text="1/3" /> <Label StyleClass="grid-cell, auto" Text="left-orver" /> </FlexLayout> </StackLayout> </ScrollView> </ContentPage>
上のスタイルシートとXAMLでこんなレイアウトが組めます。
Xamarin.AndroidでFindViewByIdを省略するやつ
が追加されるらしいです。(Kotlin Android Extensionsでできるアレ)
Slides from my presentation today. https://t.co/Pg8rjY9MKR pic.twitter.com/Pe46x3Yp1b
— Miguel de Icaza (@migueldeicaza) 2018年3月6日
(Miguelの資料より引用)
仕組みとしてはXamarin.Formsで行われている 「.xmalファイルが変更された際にmsbuildタスクが走り、x:Name
の付けられたView要素に対応するフィールドをコード生成する」 と同様なようです。
ちなみにmiguelのAndroidのスライドで説明されているやつの実体はこのPRにあるやつで、使い方はここに書いてある通りです https://t.co/WYodNPXObT たぶんここまで分かるやつおらんやろ
— Atsushi Eno (@atsushieno) 2018年3月6日
ファイルテンプレートも一緒に更新されると思いますが、xamlと違って必ずしもコードビハインドのファイルが1つに定まるわけではないので厄介そう🤔
Xamarin.Forms.FlexLayout
いつの間にかXamarin.FormsのmasterブランチにFlexLayoutが生えていたので試してみました。
いつの間にかXamarin.Flexなるディレクトリが生えてるhttps://t.co/Gk1qspwOy9
— ざまりん.ふぉーむずマン🚲 (@ticktackmobile) February 15, 2018
というかFlexLayoutが生えてるhttps://t.co/I7JW4HcbYS
— ざまりん.ふぉーむずマン🚲 (@ticktackmobile) February 15, 2018
ロードマップでは Q1 2018 Pre-Release - Q2 2018 Stable として予定されている機能です。もうすぐver.2.6.0-preとしてNuGetで普通にダウンロードできるようになると思います。
What is FlexLayout ?
端的に言うとCSSにおけるFlexboxのXamarin.Forms版がFlexLayout
です。
Xamarin.Forms標準ではこ要素を折り返して並べてくれるようなLayuoutが無いので、それだけの用途でも便利そうですね。
Xamarin.Forms.FlexLayoutちょっと使ってみた pic.twitter.com/LGgwlrWkEz
— ざまりん.ふぉーむずマン🚲 (@ticktackmobile) 2018年2月18日
内部的には
- xamarin/flexを移植した
Xamarin.Flex
名前空間 Xamarin.Flex.Item
を利用して子要素をレイアウトするFlexLayout
、レイアウト指定用のEnumやTypeConverter
といった構成になっています。
FlexLayoutのレイアウト指定
FlexLayoutがCSSに置けるFlexコンテナ、FlexLayoutの子要素がFlexアイテムに相当します。
Flexコンテナに設定するプロパティ
CSSでFlexコンテナに設定できるプロパティは、Xamarin.FormsではFlexLayouクラスのプロパティとして実装されています。
Flexbox(CSS) | FlaxLayout(XF) |
---|---|
flex-direction | Direction |
flex-wrap | Wrap |
justify-content | JustifyContent |
align-items | AlignItems |
align-content | AlignContent |
対応なし | Position |
Position
はCSSのFlexboxと異なる部分、Relative
かAbsolute
を指定できます。
- Relative:FlexLayoutのルールで配置される位置や大きさが決まる。
- Absolute:FlexアイテムのLeft,Top,Right,Bottomによって位置と大きさが決まる。(ようなんですが、それらを設定する手段が無いように見える...)
Flexアイテムに設定するプロパティ
CSSでFlexアイテムに設定できるプロパティは、Xamarin.FormsではFlexLayouクラスのAttachedPropertyとして実装されています。
Flexbox(CSS) | FlaxLayout(XF) |
---|---|
order | Order |
flex-grow | Grow |
flex-shrink | Shrink |
align-self | AlignSelf |
flex-basis | Basis |
参考
JXUGC #23 Xamarin 無料化一周年記念勉強会!で喋ってきました
2017/5/27(土)に開催されたJXUGC #23 Xamarin 無料化一周年記念勉強会!で喋ってきました。
Xamarin.Formsがさらにオープンになる変更がリリースノートでも特に言及される気配がないのでちょっと解説しました。
Xamarin.Forms 2.3.5(現時点ではプレビュー版)以降をターゲットにすれば、誰でも勝手に Xamarin.Forms.Platform.WinForms をリリースできるようになるステキな変更ですよ?
Xamarin Live Playerの仕組みを想像してた
今朝起きるとBuild 2017の2日目にXamarin Live Player(以降XLPと省略します)という技術が発表されていたので、今日はその仕組みについて想像していました。
5/12 午前
この時点では、どうやらXLPは「Mac不要でiOSアプリをビルドしてデバッグできる」技術らしいと把握していました。
「またまた皆騙されちゃってー、iOSアプリをビルドするならMacは必要、見えないところにいるだけでしょう」と想像した図がこちら。
Xamarin Live Playerについて、まだ何も試せてないけど多分こんな仕組みじゃないかな(iOSアプリの場合) pic.twitter.com/EHx7O26IN7
— ざまりん.ふぉーむずマン👀 (@ticktackmobile) 2017年5月12日
断っておくとこの想像図は間違っています。(そもそも「iOSアプリをビルドする技術」という理解が間違っている)
一応、この想像図について解説すると
iOSアプリのビルド
現在でもmachinecloudのようなMacを貸し出すクラウドサービスやVisual Studio Mobile Centerを利用することで手元にMacマシンが無くてもiOSアプリをビルドすることが可能です。
iPhoneへのアプリの配信
MicrosoftはHokkeyAppというサービスを持っていて、その中にはテスト用アプリの配布機能も含まれます。iPhoneへのアプリ配布もできそう。
デバッグ
以前からwi-fi経由でのリモートデバッグは可能でした。
とまあ、既存技術の組み合わせでできそうな気がしました。間違ってるんですけどね。
5/12 午後
新しい情報を得て考えを改めます。
@ticktackmobile クラウドでビルド、しているように見えました? 多分していたらxibもaxmlもサポートできると思うんですけど、limitationsだし、全部コードで書いている場合だけ動かせるのが現状だと思うんですよね
— Atsushi Eno (@atsushieno) 2017年5月12日
Xamarin Live Playerって、iPhone上でXamarinプログラミングできるContinuousにリモートデバッグ機能がついた感じなのかなぁ。 https://t.co/jBks1GJImJ
— くれぃんKengo Tsuruzono (@_crane_) 2017年5月12日
はい、現時点でこれが一番正解に近いツイートです。Continuous知ってる人がいてうれしみ。 https://t.co/Byq3Kg30z3
— Atsushi Eno (@atsushieno) 2017年5月12日
ここでXLPの制限事項の存在を認識します。
Xamarin Live Playerの制限事項
Xamarin公式のGuidesによると、主だった物として以下のような制限がある模様。
- Android: AXMLファイル(Xamarin.AndroidにおけるAndroidリソースの拡張子)がサポートされません。
- iOS: storyboadの一部の機能やXIBがサポートされません。
- サブクラスの実装ができません(?)
なるほど、リソースやレイアウトファイルはビルド時にAndroid/XcodeのSDKによって処理されていたはずです。 これらがサポートされないということはXLPではアプリをビルドしないと考えるべきでしょう。
Continuous
ContinuousはiOS上で動作するC#、F#用のIDE(統合開発環境)です。 iPadやiPhoneで書いたコードがその場で実行できるわけです。
ところで、iOSアプリでは実行時コンパイルができません。そのためContinuousは読み込んだコード解析して、それを再現する処理を実行しているはずです。
つまり、こんなコードを書かれた場合
// ユーザーが各コード UIlabel label = new UILabel(); label.Text = "hello world";
このようなコードに相当する処理を実行しているということです。
// Continuousが実行する処理 object variable = Activator.CreateInstance(Type.GetType("UILabel")); Type.GetType("UILabel").GetProperty("Text").SetValue(variable, "hello word", null);
ユーザーがどのクラスを使用するか不明なため、主要なライブラリはアプリに同梱しておく必要があります。その証左としてContinuousのアプリサイズは201MBあります、かなり大きいですね。
さて、話をXamarin Live Playerに戻します。
制限事項より、Android/XcodeのSDKを使ってビルドされたアプリケーションパッケージが実行されていないことが読み取れました。ということは、Visual Studioで書かれたソースコードはContinuousのようにインタープリタ形式で実行されていると考えられます。
ならば、XLPのiOS版アプリは通常よりもはるかに多きいサイズであるはず。 (補足:通常のXamarin.iOSアプリでは参照されないクラスを削ってサイズを小さくしている)
実際 197MB ありました。うん、これはもう間違いなくContinuousと同じ仕組みですね。 (ちなみにAndroidはアプリと別にライブラリをインストールできるし、実行時にコンパイルできるのでもっと小さいです、30MBくらいだそうな)
まとめ
- XLPはVisual Studio(for Mac)から転送されたソースコードをインタープリタ形式で実行している。
- Android/Xcode SDKを使ってビルドしないので通常のXamarinアプリとはできることがかなり違う。
- 動作する仕組みも違うので実機デバッグの代わりにはならない。
- 系譜としてはむしろXamarin Workbookのような一種のplaygroundに近い気がする。
- 身もふたもない言い方をすると強化されたGorilla Player。
- デバッグ可能な点は新しい。
- 通常のアプリ開発に必要な開発端末のセットアップ無しでXamarinのコードを(制限付きで)実行できるのはちょっとうれしい。
- XLPでiOSアプリを作ることはできない。もちろん公開もできない。
- Macを買わずにWindowsだけでiOSアプリをリリースできるなどという妄想は捨てる。
ちなみに、この記事を書いている時点でもまだXLP試せてません。何しろコレなもので。
やったぜ pic.twitter.com/UQ84GNUIAq
— ざまりん.ふぉーむずマン👀 (@ticktackmobile) 2017年5月12日