まずはこちらのGIF動画をご覧ください。
iPhone版のGoogle Mapsなんですが、下部エリア(丸の内付近と書かれている所)をタップするとサブコンテンツが下から生えてくる訳です。
こんな感じのUI(名前とかあるんでしょうか?)をXamarin.Formsで作ってみます。
...という訳で出来上がった物がこちらでございます。
大まかな構造として、 AbsoluteLayout
でメインコンテンツ画面の上にサブコンテンツ画面(普段は非表示)を重ねて配置し、ボタンクリックに合わせてサブコンテンツ画面をアニメーションさせています。
再現コード
Shared(またはPCL)プロジェクトにXAML付きContentPageを追加します。
ContentPage.Content
を以下の内容に上書きします。
<ContentPage.Content> <AbsoluteLayout> <!-- 最初に見えている画面 --> <StackLayout AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" Spacing="0" BackgroundColor="White" > <Label Text="メインコンテンツ" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" /> <StackLayout BackgroundColor="Navy"> <Button Text="開く" TextColor="White" BackgroundColor="Transparent" Clicked="ToggleFlyoutButtonClicked" HorizontalOptions="CenterAndExpand" /> </StackLayout> </StackLayout> <!-- 下から出てくるやつ --> <Grid x:Name="flyout" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" RowSpacing="0" IsVisible="false" BackgroundColor="White" > <Grid.RowDefinitions> <RowDefinition Height="Auto"> <RowDefinition.Height> <OnPlatform x:TypeArguments="GridLength" iOS="20" Android="0" WinPhone="0" /> </RowDefinition.Height> </RowDefinition> <RowDefinition Height="Auto"/> <RowDefinition Height="*" /> </Grid.RowDefinitions> <BoxView Grid.Row="0" Grid.RowSpan="2" Color="Maroon"/> <Button Grid.Row="1" Text="閉じる" TextColor="White" BackgroundColor="Transparent" Clicked="ToggleFlyoutButtonClicked" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" /> <Label Grid.Row="2" Text="サブコンテンツ" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" /> </Grid> </AbsoluteLayout> </ContentPage.Content>
コードビハインド(C#)
〜〜.xaml.csファイルにボタンクリックイベントのハンドラを追加します。
private async void ToggleFlyoutButtonClicked(object sender, EventArgs e) { if(flyout.IsVisible) { await flyout.TranslateTo(0, flyout.Height, 300); flyout.IsVisible = !flyout.IsVisible; } else { await flyout.TranslateTo(0, flyout.Height, 0); flyout.IsVisible = !flyout.IsVisible; await flyout.TranslateTo(0, 0, 300); } }
おまけ:全部C#で書いた場合
XAMLで書いた場合と近い印象になるよう書きました。
ContentPageのコンストラクタに挿入します。
#region 最初に見えている画面 var openButton = new Button { Text = "開く", TextColor = Color.White, BackgroundColor = Color.Transparent, HorizontalOptions = LayoutOptions.CenterAndExpand, }; var mainView = new StackLayout { Spacing = 0, BackgroundColor = Color.White, Children = { new Label { Text = "メインコンテンツ", TextColor = Color.Black, VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand, }, new StackLayout { BackgroundColor = Color.Navy, Children = { openButton } } } }; #endregion #region 下から出てくるやつ var flyoutHeader = new BoxView { Color = Color.Maroon }; var closeButton = new Button { Text = "閉じる", TextColor = Color.White, BackgroundColor = Color.Transparent, VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand }; var subContent = new Label { Text = "サブコンテンツ", TextColor = Color.Black, VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand }; var flyout = new Grid { RowSpacing = 0, IsVisible = false, BackgroundColor = Color.White, RowDefinitions = { new RowDefinition { Height = Device.OnPlatform( iOS: new GridLength(20, GridUnitType.Absolute), Android: new GridLength(0, GridUnitType.Absolute), WinPhone: new GridLength(0, GridUnitType.Absolute)) }, new RowDefinition { Height = GridLength.Auto }, new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, }, Children = { flyoutHeader, closeButton, subContent, }, }; Grid.SetRow(flyoutHeader, 0); Grid.SetRowSpan(flyoutHeader, 2); Grid.SetRow(closeButton, 1); Grid.SetRow(subContent, 2); #endregion // ルートにメイン画面とサブ画面をセット var layoutRoot = new AbsoluteLayout { Children = { mainView, flyout, } }; AbsoluteLayout.SetLayoutFlags(mainView, AbsoluteLayoutFlags.All); AbsoluteLayout.SetLayoutBounds(mainView, new Rectangle(0, 0, 1, 1)); AbsoluteLayout.SetLayoutFlags(flyout, AbsoluteLayoutFlags.All); AbsoluteLayout.SetLayoutBounds(flyout, new Rectangle(0, 0, 1, 1)); // ボタンのハンドラをセット Action toggleFlyout = async () => { if(flyout.IsVisible) { await flyout.TranslateTo(0, flyout.Height, 300); flyout.IsVisible = !flyout.IsVisible; } else { await flyout.TranslateTo(0, flyout.Height, 0); flyout.IsVisible = !flyout.IsVisible; await flyout.TranslateTo(0, 0, 300); } }; openButton.Clicked += (sender, e) => toggleFlyout(); closeButton.Clicked += (sender, e) => toggleFlyout(); // ページのContentに突っ込んで終わり! Content = layoutRoot;