ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms】 なんか下からにゅっと出てくるやつ

まずはこちらのGIF動画をご覧ください。

f:id:ticktack623:20151009032137g:plain

iPhone版のGoogle Mapsなんですが、下部エリア(丸の内付近と書かれている所)をタップするとサブコンテンツが下から生えてくる訳です。

こんな感じのUI(名前とかあるんでしょうか?)をXamarin.Formsで作ってみます。







...という訳で出来上がった物がこちらでございます。

f:id:ticktack623:20151009031533g:plain

大まかな構造として、 AbsoluteLayout でメインコンテンツ画面の上にサブコンテンツ画面(普段は非表示)を重ねて配置し、ボタンクリックに合わせてサブコンテンツ画面をアニメーションさせています。

再現コード

Shared(またはPCL)プロジェクトにXAML付きContentPageを追加します。

XAML

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;