Windows ランタイムアプリにおける BottomAppBar くらいなら Xamarin.Forms に用意されているのではと探してみましたが、やはりない!
Android はライセンスを持ってないのでできませんが、Xamarin で iOS と Windows Phone 8.0 で BottomBar というカスタム View を作ってみました
ソリューション構成はこんな感じです
BottomBar.xaml を Xamarin.Forms に作り、iOS や Windows Phone 固有の ViewRenderer として BottomBarRenderer を作る構成です
Windows Phone の MainPage.xaml.cs を見ると下記のような実装になっていました
/// <summary> /// メイン画面 /// </summary> public partial class MainPage : PhoneApplicationPage { /// <summary> /// コンストラクタ /// </summary> public MainPage() { InitializeComponent(); Forms.Init(); Content = XamarinSample.App.GetMainPage().ConvertPageToUIElement(this); } }
ページそのものではなく、Content に Xamarin.Forms のページを流し込んでいるようですね
ApplicatiionBar は PhoneApplicationPage.ApplicationBar に設定しないといけないので、この実装だと BottomBar を直接 ApplicationBar に委譲させることはできません
なので、Windows Phone の BottombarRenderer は下記のようにしました
[assembly: ExportRenderer(typeof(BottomBar), typeof(BottomBarRender))] namespace XamarinSample.WinPhone.Views { /// <summary> /// BottomBar のレンダリングクラス /// </summary> public class BottomBarRender : ViewRenderer<BottomBar, Canvas> { /// <summary> /// Element 変更イベントハンドラ /// </summary> /// <param name="e">イベント引数</param> protected override void OnElementChanged(ElementChangedEventArgs<BottomBar> e) { base.OnElementChanged(e); this.Loaded += this.OnLoaded; } /// <summary> /// 読み込み完了イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnLoaded(object sender, System.Windows.RoutedEventArgs e) { this.Loaded -= this.OnLoaded; // MainPage を引っ張り出す var currentPage = App.RootFrame.Content as PhoneApplicationPage; if (currentPage == null) { return; } currentPage.ApplicationBar = new ApplicationBar(); } } }
Frame が描画されたあとになる Page の Loaded イベント発生時に ApplicationBar を Page のプロパティに設定するというわけです
また ApplicationBar は Page を押し上げて表示されるので・・・
<?xml version="1.0" encoding="utf-8" ?> <ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamarinSample.Views.BottomBar" > <ContentView.HeightRequest> <OnPlatform x:Key="BottomHeight" x:TypeArguments="x:Double" iOS="44" Android="48" WinPhone="0" /> </ContentView.HeightRequest> </ContentView>
Xamarin.Forms の BottomBar.xaml の方は Windows Phone だけ高さ 0 にして画面の上部が余計につぶれないようにします
あとは iOS 側の BottomBarRenderer
[assembly: ExportRenderer(typeof(BottomBar), typeof(BottomBarRender))] namespace XamarinSample.iOS.Views { /// <summary> /// BottomBar のレンダリングクラス /// </summary> public class BottomBarRender : ViewRenderer<BottomBar, UIToolbar> { /// <summary> /// Element 変更イベントハンドラ /// </summary> /// <param name="e">イベント引数</param> protected override void OnElementChanged(ElementChangedEventArgs<BottomBar> e) { base.OnElementChanged(e); var toolBar = new UIToolbar() { BarStyle = UIBarStyle.Default, }; // UIToolBar をネイティブコントロールとして設定 this.SetNativeControl(toolBar); // 画面描画を要求 this.SetNeedsDisplay(); } } }
こちらは UIToolBar に委譲して画面に配置するだけ
こんな感じでそれぞれのプラットフォームで実行すると
それぞれプラットフォームに適した BottomBar が表示されました!