ScrollView

Browse sample.サンプルを参照する

.NET Multi-platform App UI (.NET MAUI) ScrollView は、コンテンツをスクロールできるビューです。 既定では、ScrollView はコンテンツを垂直方向にスクロールします。 ScrollView は子を 1 つだけ持つことができますが、他のレイアウトでもかまいません。

ScrollView は次の特性を定義します。

  • View 型の Content は、ScrollView に表示するコンテンツを表します。
  • Size 型の ContentSize は、コンテンツのサイズを表します。 これは、読み取り専用プロパティです。
  • ScrollBarVisibility 型の HorizontalScrollBarVisibility は、水平スクロール バーが表示されるタイミングを表します。
  • ScrollOrientation 型の Orientation は、ScrollView のスクロール方向を表します。 このプロパティの既定値は Vertical です。
  • double 型の ScrollX は、現在の X スクロール位置を示します。 この読み取り専用プロパティの既定値は 0です。
  • double 型の ScrollY は、現在の Y スクロール位置を示します。 この読み取り専用プロパティの既定値は 0です。
  • ScrollBarVisibility 型の VerticalScrollBarVisibility は、垂直スクロール バーが表示されるタイミングを表します。

これらのプロパティは、BindableProperty オブジェクトが基盤となります (Content プロパティは例外)。つまり、データ バインディングの対象にすることができ、スタイルを設定できます。

Content プロパティは、ScrollView クラスの ContentProperty であるため、XAML から明示的に設定する必要はありません。

警告

ScrollView オブジェクトは入れ子にしないでください。 さらに、ScrollView オブジェクトは、スクロールを提供する他のコントロール (例: CollectionViewListViewWebView) と入れ子にしないでください。

ルート レイアウトとしての ScrollView

ScrollView は子を 1 つだけ持つことができますが、他のレイアウトにすることもできます。 そのため、ScrollView がページのルート レイアウトになるのが一般的です。 子コンテンツをスクロールするには、ScrollView はコンテンツの高さとそれ自体の高さの差を計算します。 その違いは、ScrollView がコンテンツをスクロールできる量です。

StackLayout は、多くの場合、ScrollView の子になります。 このシナリオでは、ScrollView によって、StackLayout が子の高さの合計と同じ高さになります。 次に、ScrollView はコンテンツをスクロールできる量を決定できます。 StackLayout の詳細については、「 StackLayout」を参照してください。

注意事項

垂直方向の ScrollView では、VerticalOptions プロパティ を StartCenter、または End に設定しないでください。 そうすることで、ScrollView は最低限必要な高さになるように指示されます (ゼロになる可能性があります)。 .NET MAUI はこのような最終的な結果から保護されますが、起きてほしくないことを示唆するようなコードは避けることをお勧めします。

次の XAML の例では、ページ上のルート レイアウトとして ScrollView を使用しています。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ScrollViewDemos"
             x:Class="ScrollViewDemos.Views.XAML.ColorListPage"
             Title="ScrollView demo">
    <ScrollView Margin="20">
        <StackLayout BindableLayout.ItemsSource="{x:Static local:NamedColor.All}">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <StackLayout Orientation="Horizontal">
                        <BoxView Color="{Binding Color}"
                                 HeightRequest="32"
                                 WidthRequest="32"
                                 VerticalOptions="Center" />
                        <Label Text="{Binding FriendlyName}"
                               FontSize="24"
                               VerticalOptions="Center" />
                    </StackLayout>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </ScrollView>
</ContentPage>

この例では、バインド可能なレイアウトを使用して .NET MAUI で定義された Colors フィールドを表示する StackLayout に、ScrollView のコンテンツを設定しています。 既定では、ScrollView を垂直方向にスクロールさせると、さらにコンテンツが表示されます。

Screenshot of a root ScrollView layout.

同等の C# コードを次に示します。

public class ColorListPage : ContentPage
{
    public ColorListPage()
    {
        DataTemplate dataTemplate = new DataTemplate(() =>
        {
            BoxView boxView = new BoxView
            {
                HeightRequest = 32,
                WidthRequest = 32,
                VerticalOptions = LayoutOptions.Center
            };
            boxView.SetBinding(BoxView.ColorProperty, "Color");

            Label label = new Label
            {
                FontSize = 24,
                VerticalOptions = LayoutOptions.Center
            };
            label.SetBinding(Label.TextProperty, "FriendlyName");

            StackLayout horizontalStackLayout = new StackLayout
            {
                Orientation = StackOrientation.Horizontal
            };
            horizontalStackLayout.Add(boxView);
            horizontalStackLayout.Add(label);

            return horizontalStackLayout;
        });

        StackLayout stackLayout = new StackLayout();
        BindableLayout.SetItemsSource(stackLayout, NamedColor.All);
        BindableLayout.SetItemTemplate(stackLayout, dataTemplate);

        ScrollView scrollView = new ScrollView
        {
            Margin = new Thickness(20),
            Content = stackLayout
        };

        Title = "ScrollView demo";
        Content = scrollView;
    }
}

バインド可能なレイアウトの詳細については、「BindableLayout」をご覧ください。

子レイアウトとしての ScrollView

ScrollView は、別の親レイアウトに対する子レイアウトにすることができます。

ScrollView は、多くの場合、Grid の子になります。 ScrollView では、コンテンツの高さとそれ自体の高さの差を計算するために特定の高さが必要です。その差は、ScrollView がコンテンツをスクロールできる量です。 ScrollViewGrid の子である場合、特定の高さを受け取りません。 Grid では、ScrollView をできるだけ短くする必要があります。ScrollView コンテンツの高さかゼロのいずれかです。 このシナリオを処理するには、ScrollView を含む Grid 行の RowDefinition は、* に設定する必要があります。 これにより、Grid は他の子が必要としない余分なスペースすべてを ScrollView に与え、その後、ScrollView は特定の高さになります。

次の XAML の例では、Grid の子レイアウトとして ScrollView を使用します。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScrollViewDemos.Views.XAML.BlackCatPage"
             Title="ScrollView as a child layout demo">
    <Grid Margin="20"
          RowDefinitions="Auto,*,Auto">
        <Label Text="THE BLACK CAT by Edgar Allan Poe"
               FontSize="14"
               FontAttributes="Bold"
               HorizontalOptions="Center" />
        <ScrollView x:Name="scrollView"
                    Grid.Row="1"
                    VerticalOptions="FillAndExpand"
                    Scrolled="OnScrollViewScrolled">
            <StackLayout>
                <Label Text="FOR the most wild, yet most homely narrative which I am about to pen, I neither expect nor solicit belief. Mad indeed would I be to expect it, in a case where my very senses reject their own evidence. Yet, mad am I not -- and very surely do I not dream. But to-morrow I die, and to-day I would unburthen my soul. My immediate purpose is to place before the world, plainly, succinctly, and without comment, a series of mere household events. In their consequences, these events have terrified -- have tortured -- have destroyed me. Yet I will not attempt to expound them. To me, they have presented little but Horror -- to many they will seem less terrible than barroques. Hereafter, perhaps, some intellect may be found which will reduce my phantasm to the common-place -- some intellect more calm, more logical, and far less excitable than my own, which will perceive, in the circumstances I detail with awe, nothing more than an ordinary succession of very natural causes and effects." />
                <!-- More Label objects go here -->
            </StackLayout>
        </ScrollView>
        <Button Grid.Row="2"
                Text="Scroll to end"
                Clicked="OnButtonClicked" />
    </Grid>
</ContentPage>

この例では、ルート レイアウトは Grid であり、その子として、LabelScrollViewButton を使用します。 ScrollView のコンテンツは StackLayout であり、StackLayout には複数の Label オブジェクトが含まれています。 この配置により、最初の Label は常に画面に表示されますが、他の Label オブジェクトによって表示されるテキストはスクロールできます。

Screenshot of a child ScrollView layout.

同等の C# コードを次に示します。

public class BlackCatPage : ContentPage
{
    public BlackCatPage()
    {
        Label titleLabel = new Label
        {
            Text = "THE BLACK CAT by Edgar Allan Poe",
            // More properties set here to define the Label appearance
        };

        StackLayout stackLayout = new StackLayout();
        stackLayout.Add(new Label { Text = "FOR the most wild, yet most homely narrative which I am about to pen, I neither expect nor solicit belief. Mad indeed would I be to expect it, in a case where my very senses reject their own evidence. Yet, mad am I not -- and very surely do I not dream. But to-morrow I die, and to-day I would unburthen my soul. My immediate purpose is to place before the world, plainly, succinctly, and without comment, a series of mere household events. In their consequences, these events have terrified -- have tortured -- have destroyed me. Yet I will not attempt to expound them. To me, they have presented little but Horror -- to many they will seem less terrible than barroques. Hereafter, perhaps, some intellect may be found which will reduce my phantasm to the common-place -- some intellect more calm, more logical, and far less excitable than my own, which will perceive, in the circumstances I detail with awe, nothing more than an ordinary succession of very natural causes and effects." });
        // More Label objects go here

        ScrollView scrollView = new ScrollView();
        scrollView.Content = stackLayout;
        // ...

        Title = "ScrollView as a child layout demo";
        Grid grid = new Grid
        {
            Margin = new Thickness(20),
            RowDefinitions =
            {
                new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) },
                new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
                new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) }
            }
        };
        grid.Add(titleLabel);
        grid.Add(scrollView, 0, 1);
        grid.Add(button, 0, 2);

        Content = grid;
    }
}

向き

ScrollView には、ScrollView のスクロール方向を表す Orientation プロパティがあります。 このプロパティは ScrollOrientation 型であり、次の要素を定義します。

  • Vertical は、ScrollView が垂直方向にスクロールすることを示します。 この要素は、Orientation プロパティの既定値です。
  • Horizontal は、ScrollView が水平にスクロールすることを示します。
  • Both は、ScrollView が水平方向と垂直方向にスクロールすることを示します。
  • Neither は、 ScrollView がスクロールしないことを示します。

ヒント

Orientation プロパティを Neither に設定すると、スクロールを無効にできます。

スクロールの検出

ScrollView は、スクロールが発生したことを示すために発生する Scrolled イベントを定義します。 Scrolled イベントに付随する ScrolledEventArgs オブジェクトには、ScrollXScrollY のプロパティがあり、両方とも double 型です。

重要

ScrolledEventArgs.ScrollXScrolledEventArgs.ScrollY のプロパティは負の値を持つことがあります。スクロールして ScrollView の開始位置に戻るときに発生するバウンス効果が原因です。

次の XAML の例では、Scrolled イベントのイベント ハンドラーを設定する ScrollView を示します。

<ScrollView Scrolled="OnScrollViewScrolled">
    ...
</ScrollView>

同等の C# コードを次に示します。

ScrollView scrollView = new ScrollView();
scrollView.Scrolled += OnScrollViewScrolled;

この例では、OnScrollViewScrolled イベントが発生したときに Scrolled イベント ハンドラーが実行されます。

void OnScrollViewScrolled(object sender, ScrolledEventArgs e)
{
    Console.WriteLine($"ScrollX: {e.ScrollX}, ScrollY: {e.ScrollY}");
}

この例では、OnScrollViewScrolled イベント ハンドラーは、イベントに付随する ScrolledEventArgs オブジェクトの値を出力します。

Note

Scrolled イベントは、ユーザーが開始したスクロールとプログラムによるスクロールに対して発生します。

プログラムでスクロールする

ScrollView は、ScrollView を非同期的にスクロールする 2 つの ScrollToAsync メソッドを定義します。 オーバーロードの 1 つは ScrollView 内の指定した位置までスクロールし、もう 1 つは指定した要素をビューにスクロールします。 どちらのオーバーロードにも、スクロールをアニメーション化するかどうかを示すために使用できる追加の引数があります。

重要

ScrollView.Orientation プロパティが Neither に設定されている場合、ScrollToAsync メソッドはスクロールしません。

位置をスクロールして表示する

ScrollView 内の位置は、doublexy の引数を受け入れる ScrollToAsync メソッドを使用してスクロールできます。 scrollView という名前の垂直 ScrollView オブジェクトを指定する場合、次の例では、ScrollView の上部からデバイスに依存しない 150 単位分までスクロールする方法を示します。

await scrollView.ScrollToAsync(0, 150, true);

ScrollToAsync の 3 番目の引数は、ScrollView をプログラムでスクロールするときにスクロール アニメーションを表示するかどうかを決定する animated 引数です。

要素をビューにスクロールする

ScrollView 内の要素は、ElementScrollToPosition の引数を受け入れる ScrollToAsync メソッドを使用してビューにスクロールできます。 scrollView という名前の垂直 ScrollView と、label という名の Label を指定する場合、次の例は要素をビューにスクロールする方法を示しています。

await scrollView.ScrollToAsync(label, ScrollToPosition.End, true);

ScrollToAsync の 3 番目の引数は、ScrollView をプログラムでスクロールするときにスクロール アニメーションを表示するかどうかを決定する animated 引数です。

要素をビューにスクロールする場合、スクロールが完了した後の要素の正確な位置は、ScrollToAsync メソッドの 2 番目の引数 position で設定できます。 この引数は ScrollToPosition 列挙要素を受け入れます。

  • MakeVisible は、要素が ScrollView に表示されるまでスクロールする必要があることを示します。
  • Start は、要素を ScrollView の開始位置までスクロールする必要があることを示します。
  • Center は、要素を ScrollView の中心までスクロールする必要があることを示します。
  • End は、要素を ScrollView の最後までスクロールする必要があることを示します。

スクロール バーの表示

ScrollView は、バインド可能なプロパティによってサポートされる HorizontalScrollBarVisibilityVerticalScrollBarVisibility のプロパティを定義します。 これらのプロパティは、水平スクロール バーと垂直スクロール バーのどちらを表示するかを表す ScrollBarVisibility 列挙型を取得または設定します。 ScrollBarVisibility 列挙体を使って、次のメンバーを定義できます。

  • Default は、プラットフォームの既定のスクロール バーの動作を示し、HorizontalScrollBarVisibility プロパティと VerticalScrollBarVisibility プロパティの既定値です。
  • Always は、コンテンツがビューに収まる場合でもスクロール バーが表示されることを示します。
  • Never は、コンテンツがビューに収まらない場合でもスクロール バーが表示されないことを示します。