Xamarin.Forms ScrollView

Download Sample下载示例

Xamarin.Forms ScrollView

ScrollView 是一种能够滚动其内容的布局。 ScrollView 类派生自 Layout 类,默认情况下垂直滚动其内容。 ScrollView 只能有一个子项,但也可以是其他布局。

警告

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

ScrollView 定义以下属性:

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

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

提示

若要获取最佳可能布局性能,请遵循优化布局性能中的准则。

ScrollView 作为根布局

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

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

注意

在垂直 ScrollView 中,避免将 VerticalOptions 属性设置为 StartCenterEnd。 这样做会告诉 ScrollView 只与它需要的高度一样高,这可能为零。 虽然 Xamarin.Forms 可以避免这种最终性,但最好避免会建议你不想发生的事情的代码。

以下 XAML 示例将 ScrollView 作为页面上的根布局:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ScrollViewDemos"
             x:Class="ScrollViewDemos.Views.ColorListPage"
             Title="ScrollView demo">
    <ScrollView>
        <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,它使用可绑定布局来显示由 Xamarin.Forms 定义的 Color 字段。 默认情况下,ScrollView 垂直滚动来显示更多内容:

Screenshot of a root ScrollView layout

等效 C# 代码如下:

public class ColorListPageCode : ContentPage
{
    public ColorListPageCode()
    {
        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,
                Children = { boxView, label }
            };
            return horizontalStackLayout;
        });

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

        ScrollView scrollView = new ScrollView { Content = stackLayout };

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

有关可绑定布局的详细信息,请参阅 Xamarin.Forms 中的可绑定布局

ScrollView 作为子布局

ScrollView 可以是不同父布局的子布局。

ScrollView 通常是 StackLayout 的子级。 ScrollView 需要特定的高度来计算其内容高度与其自身高度之间的差值,该差值是 ScrollView 可以滚动其内容的量。 当 ScrollViewStackLayout 的子级时,它不会接收特定高度。 StackLayout 希望 ScrollView 尽可能短,它是 ScrollView 内容的高度或零。 若要处理此方案,应将 ScrollViewVerticalOptions 属性设置为 FillAndExpand。 这将导致 StackLayoutScrollView 提供其他子级不需要的所有额外空间,然后 ScrollView 将具有特定高度。

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

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScrollViewDemos.Views.BlackCatPage"
             Title="ScrollView as a child layout demo">
    <StackLayout Margin="20">
        <Label Text="THE BLACK CAT by Edgar Allan Poe"
               FontSize="Medium"
               FontAttributes="Bold"
               HorizontalOptions="Center" />
        <ScrollView VerticalOptions="FillAndExpand">
            <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>
    </StackLayout>
</ContentPage>

在此示例中,有两个 StackLayout 对象。 第一个 StackLayout 是根布局对象,它有一个 Label 对象和一个 ScrollView 作为子级。 ScrollView 的内容为 StackLayout,而 StackLayout 包含多个 Label 对象。 这样的安排可以确保第一个 Label 始终显示在屏幕上,而其他 Label 对象显示的文本可以滚动:

Screenshot of a child ScrollView layout

等效 C# 代码如下:

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

        ScrollView scrollView = new ScrollView
        {
            VerticalOptions = LayoutOptions.FillAndExpand,
            Content = new StackLayout
            {
                Children =
                {
                    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
                }
            }
        };

        Title = "ScrollView as a child layout demo";
        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = { titleLabel, scrollView }
        };
    }
}

方向

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 方法不会导致滚动。

将位置滚动到视图中

可以使用接受 doublexy 参数的 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 指示滚动条将不可见,即使内容大小不适合视图。