タイトルではちょっとわかりにくいかもですが、 Xamarin.Forms のいいところは、
iOS と Android で UI を共通化させることで、コードの記述量がへることです。
そういうことで、私も iOS と Android で共通の UI を使っているのですが、
iOS もしくは、 Android だけで表示させたいパーツが有るときの方法みたいな。
前に上げた記事において、ツールバーの左側にアイテムを追加しました。
Xamarin.Forms の ToolBarItems で左に置く
私の場合、モーダルダイアログで使用しているのですが、 iOS だと戻るボタンはありませんが、
Android だと、ハードウェアで戻るボタンがすでに存在しているため、必要ありません。
こういった、Android や WP ではいるけど、 iOS では必要ないといった場合の制御を行います。
必要なのは、 Behavior と Attached Property の2つ。
Grid
や DockPanel
みたいな感じで使えるようにしたいと思います。
仕組みとしては、 Attached Property で設定された値を、親コントロールへ通知し、
該当コントロールを Children
から削除します。
ということでまずは Behavior から
なお、どちらも Windows Phone は省いていますが、同様に実装できます。
public class PlatformBehavior : Behavior<Layout<View>> { private Layout<View> _layout; private IDisposable _disposable; private bool _flag; protected override void OnAttachedTo(Layout<View> bindable) { this._layout = bindable; this._disposable = Observable.Timer(TimeSpan.Zero, TimeSpan.FromMilliseconds(10)) .Select(_ => this._flag) .DistinctUntilChanged() .Where(w => w) .Repeat() .Subscribe(_ => this.DoAction()); bindable.ChildAdded += Bindable_ChildAdded; base.OnAttachedTo(bindable); } protected override void OnDetachingFrom(Layout<View> bindable) { base.OnDetachingFrom(bindable); bindable.ChildAdded -= Bindable_ChildAdded; this._disposable.Dispose(); } private void Bindable_ChildAdded(object sender, ElementEventArgs e) { this._flag = true; } private void DoAction() { var children = this._layout.Children; foreach (var child in children) { if (Device.OS == TargetPlatform.Android) { if (!(bool)child.GetValue(PlatformControl.AndroidProperty)) { this._layout.Children.Remove(child); } } if (Device.OS == TargetPlatform.iOS) { if (!(bool)child.GetValue(PlatformControl.iOSProperty)) { this._layout.Children.Remove(child); } } } this._flag = false; } }
次に Attached Property
public class PlatformControl { // iOS public static bool GetiOS(BindableObject obj) { return (bool)obj.GetValue(iOSProperty); } public static void SetiOS(BindableObject obj, bool value) { obj.SetValue(iOSProperty, value); } public static readonly BindableProperty iOSProperty = BindableProperty.CreateAttached("iOS", typeof(bool), typeof(PlatformControl), true); // Android public static bool GetAndroid(BindableObject obj) { return (bool)obj.GetValue(AndroidProperty); } public static void SetAndroid(BindableObject obj, bool value) { obj.SetValue(AndroidProperty, value); } public static readonly BindableProperty AndroidProperty = BindableProperty.CreateAttached("Android", typeof(bool), typeof(PlatformControl), true); }
これで完成です。
XAML では、下のようにして使います(この程度なら OnPlatform
でもいけます)。
<Grid> <Grid.Behaviors> <behaviors:PlatformBehavior /> </Grid.Behaviors> <Label Text="iOS Only" HorizontalOptions="StartAndExpand" e:PlatformControl.iOS="True" e:PlatformControl.Android="False" /> <Label Text="Android Only" HorizontalOptions="StartAndExpand" e:PlatformControl.iOS="False" e:PlatformControl.Android="True" /> </Grid>
e:PlatformControl.iOS
を True
にすると表示、 False
にすると非表示です。
デフォルトは True
なので、表示する場合は省略できます。
いつもながら、もしかしたら標準 API で提供されているかもしれません。
ということで、ではでは。