.NET MAUI(.NET 多平台应用 UI)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 对象不应与其他提供滚动的控件嵌套,例如 CollectionView, ListView和 WebView。
ScrollView 作为根布局
一个 ScrollView 只能有一个子元素,可以是其他布局。 因此,ScrollView 常被用作页面的根布局。 若要滚动其子内容,ScrollView 会计算其内容高度与其自身高度之间的差值。 ScrollView 可以滚动其内容的数量就是这种差异。
A StackLayout 通常是 ScrollView 的子元素。 在此方案中,ScrollView导致StackLayout的高度等于其子级高度之和。 然后, ScrollView 可以确定其内容可滚动的量。 有关StackLayout的详细信息,请参阅StackLayout。
注意
在垂直ScrollView中,避免将VerticalOptions属性设置为Start或 CenterEnd。 这样做会告知 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 垂直滚动可显示更多内容:
等效的 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可以滚动其内容的范围。 当ScrollView是Grid的子元素时,它没有特定的高度。 希望GridScrollView尽可能短,可以是ScrollView内容的高度或者为零。 要处理这种情况,应将包含ScrollView的Grid行的RowDefinition设置为*。 这将导致 Grid 将所有其他子级不需要的额外空间分配给 ScrollView,而 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="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,其子级包括Label、ScrollView和Button。 ScrollView 的内容为 StackLayout,其中 StackLayout 包含多个 Label 对象。 这种排列可确保第一个 Label 始终在屏幕上显示,而其他 Label 对象显示的文本可以滚动:
等效的 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对象具有ScrollX和ScrollY属性,且它们都是double类型。
重要
由于滚动回到ScrollView的起始位置时会出现弹跳效果,ScrolledEventArgs.ScrollX和ScrolledEventArgs.ScrollY属性可以具有负值。
下面的 XAML 示例演示了一个 ScrollView 为 Scrolled 事件设置事件处理程序:
<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方法并接受doublex和y参数,在ScrollView内滚动到某个位置。 假设有一个名为ScrollView垂直scrollView对象,以下示例演示如何从顶部ScrollView滚动到 150 个独立于设备的单位:
await scrollView.ScrollToAsync(0, 150, true);
第三个参数是ScrollToAsync参数,该参数animated确定在以编程方式滚动 a ScrollView时是否显示滚动动画。
将元素滚动到视图中
可以使用ScrollToAsync方法,该方法接受Element和ScrollToPosition参数,将ScrollView中的元素滚动到视图中。 假设有一个命名为scrollView的垂直ScrollView和一个命名为label的Label,以下示例演示如何将元素滚动到视图中:
await scrollView.ScrollToAsync(label, ScrollToPosition.End, true);
第三个参数是ScrollToAsync参数,该参数animated确定在以编程方式滚动 a ScrollView时是否显示滚动动画。
将元素滚动到视图中时,可以使用方法的第二个参数positionScrollToAsync设置滚动完成后元素的确切位置。 此参数接受 ScrollToPosition 枚举成员:
-
MakeVisible指示元素应滚动,直到它在 ScrollView 中可见。 指示元素应滚动到 的开头。 -
Center指示元素应滚动到 ScrollView 的中心。 -
End指示元素应滚动到该 ScrollView元素的末尾。
滚动条可见性
ScrollView定义HorizontalScrollBarVisibility和VerticalScrollBarVisibility属性,这些属性由可绑定属性提供支持。 这些属性获取或设置一个 ScrollBarVisibility 枚举值,该值表示水平滚动条还是垂直滚动条可见。
ScrollBarVisibility 枚举定义以下成员:
-
Default指示平台的默认滚动条行为,并且是默认值HorizontalScrollBarVisibility和VerticalScrollBarVisibility属性。 -
Always指示滚动条会始终可见,即使内容完全适合视图也是如此。 -
Never指示滚动条将不可见,即使内容超出了视图范围。
浏览示例