ScrollView

浏览示例。 浏览示例

.NET Multi-platform App UI (.NET MAUI) ScrollView 是一个能够滚动其内容的视图。 默认情况下,ScrollView 垂直滚动其内容。 ScrollView 只能有一个子项,但也可以是其他布局。

ScrollView 定义以下属性:

  • Content,类型为 View,表示要在 ScrollView 中显示的内容。
  • ContentSize,类型为 Size,表示内容的大小。 这是只读属性。
  • HorizontalScrollBarVisibility,类型为 ScrollBarVisibility,表示水平滚动条何时可见。
  • Orientation,类型为 ScrollOrientation,表示 ScrollView 的滚动方向。 此属性的默认值为 Vertical
  • ScrollX,类型为 double,表示当前的 X 轴滚动位置。 此只读属性的默认值为 0。
  • ScrollY,类型为 double,表示当前的 Y 轴滚动位置。 此只读属性的默认值为 0。
  • VerticalScrollBarVisibility,类型为 ScrollBarVisibility,表示垂直滚动条何时可见。

这些属性由 BindableProperty 对象提供支持,但 Content 属性除外;也就是说,它们可以作为数据绑定的目标,并能进行样式设置。

由于 Content 属性是 ScrollView 类的 ContentProperty,因此不需要通过 XAML 显式设置。

警告

不应嵌套 ScrollView 对象。 此外,ScrollView 对象不应与提供滚动的其他控件(如 CollectionViewListViewWebView)嵌套。

ScrollView 作为根布局

ScrollView 只能有一个子项,该子项可以是其他布局。 因此,ScrollView 通常是页面上的根布局。 要滚动其子内容,ScrollView 会计算其内容的高度与其自身高度之间的差值。 该差值是 ScrollView 可以滚动其内容的量。

StackLayout 通常是 ScrollView 的子项。 在此应用场景中,ScrollView 导致 StackLayout 与其子项的高度总和一样高。 然后,ScrollView 可以确定其内容可以滚动的量。 有关 StackLayout 的详细信息,请参阅 StackLayout

注意

在垂直 ScrollView 中,避免将 VerticalOptions 属性设置为 StartCenterEnd。 这样做会告诉 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>

在此示例中,ScrollView 将其内容设置为 StackLayout,后者使用可绑定布局来显示由 .NET MAUI 定义的 Colors 字段。 默认情况下,ScrollView 垂直滚动来显示更多内容:

根 ScrollView 布局的屏幕截图。

等效 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 内容的高度或零。 要处理这种情况,应将包含 ScrollViewGrid 行的 RowDefinition 设置为 *。 这将导致 GridScrollView 提供其他子级不需要的所有额外空间,然后 ScrollView 将具有特定高度。

以下 XAML 示例将 ScrollView 作为 Grid 的子布局:

<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,其子级为 LabelScrollViewButtonScrollView 的内容为 StackLayout,而 StackLayout 包含多个 Label 对象。 这样的安排可以确保第一个 Label 始终显示在屏幕上,而其他 Label 对象显示的文本可以滚动:

子 ScrollView 布局的屏幕截图。

等效 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 具有 Orientation 属性,该属性表示 ScrollView 的滚动方向。 此属性的类型为 ScrollOrientation,它定义了以下成员:

  • Vertical 表示 ScrollView 将垂直滚动。 此成员是 Orientation 属性的默认值。
  • Horizontal 表示 ScrollView 将水平滚动。
  • Both 表示 ScrollView 将水平和垂直滚动。
  • Neither 表示 ScrollView 不会滚动。

提示

通过将 Orientation 属性设置为 Neither,可以禁用滚动。

检测滚动

ScrollView 定义一个 Scrolled 事件,引发该事件时表示发生了滚动。 Scrolled 事件随附的 ScrolledEventArgs 对象包含类型为 doubleScrollXScrollY 属性。

重要说明

ScrolledEventArgs.ScrollXScrolledEventArgs.ScrollY 属性可以具有负值,因为在滚动回 ScrollView 的起始处时,会产生反弹效果。

下面的 XAML 示例显示了为 Scrolled 事件设置事件处理程序的 ScrollView

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

等效 C# 代码如下:

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

在此示例中,当触发 Scrolled 事件时,将执行 OnScrollViewScrolled 事件处理程序:

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

在此示例中,OnScrollViewScrolled 事件处理程序会输出随附相应事件的 ScrolledEventArgs 对象的值。

注意

对于用户启动的滚动和编程滚动,会引发 Scrolled 事件。

以编程方式滚动

ScrollView 定义了两个 ScrollToAsync 方法,它们可以异步滚动 ScrollView。 其中一个重载滚动到 ScrollView 中的指定位置,而另一个重载将指定的元素滚动到视图中。 这两个重载都有一个附加参数,可用于表示是否对滚动进行动画处理。

重要说明

ScrollView.Orientation 属性设置为 Neither 时,ScrollToAsync 方法不会导致滚动。

将位置滚动到视图中

可以使用接受 double xy 参数的 ScrollToAsync 方法滚动到 ScrollView 中的某个位置。 以下示例显示了在给定一个名为 scrollView 的垂直 ScrollView 对象时,如何从 ScrollView 的顶部滚动到 150 个与设备无关的单元:

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

ScrollToAsync 的第三个参数是 animated 参数,它将确定以编程方式滚动 ScrollView 时是否显示滚动动画。

将元素滚动到视图中

ScrollView 中的元素可以使用接受 ElementScrollToPosition 参数的 ScrollToAsync 方法滚动到视图中。 下面的示例显示了在给定一个名为 scrollView 的垂直 ScrollView 和一个名为 labelLabel 时,如何将元素滚动到视图中:

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

ScrollToAsync 的第三个参数是 animated 参数,它将确定以编程方式滚动 ScrollView 时是否显示滚动动画。

将元素滚动到视图中时,可以使用 ScrollToAsync 方法的第二个参数 position 设置滚动完成后元素的确切位置。 此参数接受一个 ScrollToPosition 枚举成员:

  • MakeVisible 表示应滚动该元素,直到它在 ScrollView 中可见。
  • Start 表示元素应滚动到 ScrollView 的起始处。
  • Center 表示应将元素滚动到 ScrollView 的中心。
  • End 表示元素应滚动到 ScrollView 的末尾。

滚动条可见性

ScrollView 定义由可绑定属性支持的 HorizontalScrollBarVisibilityVerticalScrollBarVisibility 属性。 这些属性将获取或设置 ScrollBarVisibility 枚举值,该值表示水平或垂直滚动条是否可见。 ScrollBarVisibility 枚举定义以下成员:

  • Default 表示平台的默认滚动条行为,是 HorizontalScrollBarVisibilityVerticalScrollBarVisibility 属性的默认值。
  • Always 指示滚动条将可见,即使内容大小适合视图。
  • Never 指示滚动条将不可见,即使内容大小不适合视图。