Xamarin.FormsのShellを一から使ってみる
環境
- Visual Studio 2019 16.4 preview
- Xamarin.Forms 4.3 preview
Shellってどんなコントロール?
横から出てくるメニューが特徴的なUIコントロール.その他にもサーチバーやタブといった機能が統合されている.
それぞれのページが同列の関係のときに使うと良い. 親子関係のような構成の場合,NavigationViewを使うといいと思う.
Shellページの作成
まずはShellページを作るのだけれど,Visual Studioの項目の新規追加ではShellのテンプレートはないので,まずはContent View
テンプレートを選択して作成する.
ここではMainShell
という名前をつけた.
次にContentPage
タグをShell
に変更し,ContentPage.Content
など,中のタグを削除する.
<?xml version="1.0" encoding="UTF-8"?> <Shell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="XamarinFormsShellPractice.MainShell"> </Shell>
コードビハインドの修正
MainShell.xaml.csを開くと,MainShellクラスはデフォルトではContentPage
を継承している.
これをShell
を継承するように変更する.
namespace XamarinFormsShellPractice { public partial class MainShell : Shell { public MainShell() { InitializeComponent(); } } }
アプリケーションのMainPageを変更する
App.xaml.cs
を開くと,AppクラスのコンストラクタにMainPage = new MainPage();
が見つかると思います.
これを以下のようにします.
MainPage = new MainShell();
ここまでで準備が整いました.ソリューションをビルドしましょう.
この時点ではShellの中身が何もないのでデプロイ時にエラーになります.
Shellの構成
ShellではFlyoutItem
, TabBar
, Tab
, ShellContent
からなります.
Shell
はFlyoutItem
, またはTabBar
を子要素としてもつことができます.
FlyoutItemはFlyout(ドロワーメニューっていうの?)を使う場合に必要です.
TabBarは下部のタブバーを表します.Flyoutメニューは表示されません.
Tabは下タブバーの一つのタブを表します.FlyoutItemまたはTabBarの中に複数のTabを設けると,下タブが表示されます.
ShellContentをTab内に配置すると上タブが付きます.
あと,MenuItem
も置ける.メニューだもんね...
FlyoutItem
Shellの中にFlyoutItem要素を入れると,ハンバーガーメニューや横スワイプでひょっこり出てくるドロワーメニューが表示される.
<FlyoutItem Title="First"> <ShellContent> <local:MyPage1/> </ShellContent> </FlyoutItem> <FlyoutItem Title="Second"> <ShellContent> <local:MyPage2/> </ShellContent> </FlyoutItem>
TabBar(下タブ)
FlyoutItem
の中に複数のTab
が存在する場合,下部にタブバーが表示される.ハンバーガーメニューも表示される.ただしFlyoutItemにFlyoutDisplayOptions="AsMultipleItems"
をつけておく.こと
これをつけることでFlyoutItem内のそれぞれのTabがFlyoutItemとしてFlyoutに表示されるようになる..これをつけないとFlyout自体は表示されるけれど中身は空.
<FlyoutItem Title="First" FlyoutDisplayOptions="AsMultipleItems"> <Tab Title="Tab1"> <ShellContent ContentTemplate="{DataTemplate local:MyPage1}"/> </Tab> <Tab Title="Tab2"> <ShellContent ContentTemplate="{DataTemplate local:MyPage2}"/> </Tab> </FlyoutItem>
または,各TabをFlyoutItemで囲う.
<FlyoutItem Title="First"> <Tab Title="Tab1"> <ShellContent ContentTemplate="{DataTemplate local:MyPage1}"/> </Tab> </FlyoutItem> <FlyoutItem Title="Second"> <Tab Title="Tab2"> <ShellContent ContentTemplate="{DataTemplate local:MyPage2}"/> </Tab> </FlyoutItem>
TabBar
の中にTab
を書く.この場合,ハンバーガーメニューは表示されず,Flyoutも出ない.
<TabBar> <Tab Title="Tab1"> <ShellContent ContentTemplate="{DataTemplate local:MyPage1}"/> </Tab> <Tab Title="Tab2"> <ShellContent ContentTemplate="{DataTemplate local:MyPage2}"/> </Tab> </TabBar>
Flyoutが必要かどうかで使い分けるとよい.
上記のように<ShellContent ContentTemplate="{DataTemplate local:MyPage1}"/>
と記述すると,アプリ起動時にページのインスタンスが生成されるのではなく,ページに遷移するときにインスタンスが作成される.
上タブ
FlyoutItem
の中にTab
を一つ置いて,その中に複数のShellContent
を置くと上部にタブがつく.
複数の ShellContent オブジェクトが Tab にある場合は、上部のタブによってそのオブジェクトをナビゲートできます。
<FlyoutItem Title="Second"> <Tab Title="Tab2"> <ShellContent Title="Tab1" ContentTemplate="{DataTemplate local:MyPage1}"/> <ShellContent Title="Tab2" ContentTemplate="{DataTemplate local:MyPage2}"/> </Tab> </FlyoutItem>
というように、Shellの階層構造は、 FlyoutItem →Tab(下タブ)→上タブ
となっている。
ドロワーメニューにヘッダーを表示する
Shell.FlyoutHeaderTemplate
を使うことで,ヘッダー領域を表示できる.
ContentView
の中におしゃれなUIを入れることができる.
<Shell.FlyoutHeaderTemplate> <DataTemplate> <ContentView BackgroundColor="Pink" HeightRequest="150"> <Label Text="Header" TextColor="Black" VerticalOptions="Center" HorizontalOptions="Center"/> </ContentView> </DataTemplate> </Shell.FlyoutHeaderTemplate>
デフォルトではスワイプ時に変化はしない.
しかし,Shell開始タグ内にFlyoutHeaderBehavior="CollapseOnScroll"
を記述することで,上下スワイプ時にサイズを自動で変化させてくれる.
<Shell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:local="clr-namespace:XamarinFormsShellPractice" FlyoutHeaderBehavior="CollapseOnScroll" x:Class="XamarinFormsShellPractice.MainShell">
上スワイプしたときに縮む↓
Navigationでのページ遷移先でタブを表示させない
Navigation.PushAsync
でページ遷移したとき,遷移先でもタブが表示される.
そして,この遷移先でのタブは動作しない.
遷移先でタブを表示させたくない場合は,以下のように遷移直前に非表示にすることで実現できる.
private async void Button_Clicked(object sender, EventArgs e) { var mp2 = new MyPage2(); Shell.SetTabBarIsVisible(mp2, false); await Shell.Current.Navigation.PushAsync(mp2, true); }
各ページの生成タイミング
Shell内で切り替えられる各ページはアプリケーション起動時.
これによってパフォーマンスに影響を及ぼすこともある.
必要なときに生成することもできる.
<FlyoutItem Title="First"> <ShellContent ContentTemplate="{DataTemplate local:MyPage1}"/> </FlyoutItem> <FlyoutItem Title="Second"> <ShellContent ContentTemplate="{DataTemplate local:MyPage2}"/> </FlyoutItem>