ScrollView (滚动视图)

浏览示例。 浏览示例

.NET MAUI(.NET 多平台应用 UI)ScrollView 是一种能够滚动其内容的视图。 默认情况下, ScrollView 垂直滚动其内容。 一个ScrollView只能有一个子元素,尽管这个子元素可以是其他布局。

ScrollView 定义以下属性:

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

这些属性由 BindableProperty 对象提供支持,除了 Content 属性,这意味着它们可以成为数据绑定和样式的目标。

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

警告

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

ScrollView 作为根布局

一个 ScrollView 只能有一个子元素,可以是其他布局。 因此,ScrollView 常被用作页面的根布局。 若要滚动其子内容,ScrollView 会计算其内容高度与其自身高度之间的差值。 ScrollView 可以滚动其内容的数量就是这种差异。

A 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 x:DataType="local:NamedColor">
                    <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, static (NamedColor nc) => nc.Color);

            Label label = new Label
            {
                FontSize = 24,
                VerticalOptions = LayoutOptions.Center
            };
            label.SetBinding(Label.TextProperty, static (NamedColor nc) => nc.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 可以是不同父布局的子布局。

A ScrollView 通常是一个 Grid的子节点。 一个ScrollView需要特定的高度来计算其内容高度与自身高度之间的差值,而这个差值就是ScrollView可以滚动其内容的范围。 当ScrollViewGrid的子元素时,它没有特定的高度。 希望GridScrollView尽可能短,可以是ScrollView内容的高度或者为零。 要处理这种情况,应将包含ScrollViewGrid行的RowDefinition设置为*。 这将导致 Grid 将所有其他子级不需要的额外空间分配给 ScrollView,而 ScrollView 将具有特定的高度。

下面的 XAML 示例中,ScrollViewGrid 的子布局:

<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="Fill"
                    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 不会滚动。

小窍门

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

检测滚动

ScrollView 定义一个 Scrolled 事件,用于指示发生了滚动。 ScrolledEventArgs事件附带的Scrolled对象具有ScrollXScrollY属性,且它们都是double类型。

重要

由于滚动回到ScrollView的起始位置时会出现弹跳效果,ScrolledEventArgs.ScrollXScrolledEventArgs.ScrollY属性可以具有负值。

下面的 XAML 示例演示了一个 ScrollViewScrolled 事件设置事件处理程序:

<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 定义了两种异步滚动ScrollView的方法。 其中一个重载将ScrollView滚动到指定位置,而另一个重载将指定元素滚动至可见区域。 这两个重载都有一个附加参数,可用于指示是否对滚动进行动画处理。

重要

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

将某个位置滚动显示在视图中

可以使用ScrollToAsync方法并接受doublexy参数,在ScrollView内滚动到某个位置。 假设有一个名为ScrollView垂直scrollView对象,以下示例演示如何从顶部ScrollView滚动到 150 个独立于设备的单位:

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

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

将元素滚动到视图中

可以使用ScrollToAsync方法,该方法接受ElementScrollToPosition参数,将ScrollView中的元素滚动到视图中。 假设有一个命名为scrollView的垂直ScrollView和一个命名为labelLabel,以下示例演示如何将元素滚动到视图中:

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

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

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

  • MakeVisible 指示元素应滚动,直到它在 ScrollView 中可见。
  • 指示元素应滚动到 的开头。
  • Center 指示元素应滚动到 ScrollView 的中心。
  • End 指示元素应滚动到该 ScrollView元素的末尾。

滚动条可见性

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

  • Default 指示平台的默认滚动条行为,并且是默认值 HorizontalScrollBarVisibilityVerticalScrollBarVisibility 属性。
  • Always 指示滚动条会始终可见,即使内容完全适合视图也是如此。
  • Never 指示滚动条将不可见,即使内容超出了视图范围。