主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2015/12/15
タイトルではちょっとわかりにくいかもですが、 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 で提供されているかもしれません。
ということで、ではでは。