Xamarin窗体:如何检测滚动视图(或扩展器)的末尾或顶部到达



当滚动视图到达末尾或顶部时,我需要加载更多数据。我在这里找到了相同的线索,但在那上面,我不明白什么是MyScrollView

private void OnScrolled(object sender, ScrolledEventArgs e)
{
MyScrollView scrollView = sender as MyScrollView;
double scrollingSpace = scrollView.ContentSize.Height - scrollView.Height;
if (scrollingSpace <= e.ScrollY)
{
//reached end
}
}

我使用ItemAppearing事件在ListView中实现了相同的功能。但目前,我在UI上使用Expander来显示数据。扩展器到达结尾和开始时是否存在任何相同的事件?扩展器在滚动视图中,这就是我开始研究滚动视图结束事件的原因。

当滚动视图到达结束或开始时,我如何触发某种事件?

更新

我的滚动视图内容如下,它包含BindableLayoutExpander

<ScrollView
x:Name="MyScrollView"
Scrolled="OnScrolled">
<StackLayout BindableLayout.ItemsSource="{Binding AllItems,Mode=TwoWay}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Expander>
</Expander>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>

MyScrollView可能是使用ScrollView的自定义视图。这是我使用Listview的示例代码。您也可以将其应用于自定义滚动视图。

自定义列表视图.cs

public class CustomListView : ListView
{
public CustomListView()
{
}
}

iOS

[assembly: ExportRenderer(typeof(CustomListView), typeof(CustomListViewRenderer))]
namespace YOUR_PROJECT_NAME.iOS.Renderers
{
public class CustomListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Element != null)
{
Control.AlwaysBounceVertical = Element.IsPullToRefreshEnabled;
Control.Bounces = Element.IsPullToRefreshEnabled;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(Element.IsPullToRefreshEnabled))
{
Control.AlwaysBounceVertical = Element.IsPullToRefreshEnabled;
Control.Bounces = Element.IsPullToRefreshEnabled;
}
}
}
}

安卓

No custom renderer is needed

Xaml

<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0"
x:Name="DashboardBarGrid"
BackgroundColor="#263A43"
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid Grid.Row="0"
HorizontalOptions="CenterAndExpand" VerticalOptions="Center">
<Label Text="Title" TextColor="White"/>
</Grid>
</Grid>
<controls:CustomListView Grid.Row="1" ItemsSource="{Binding Items}" Scrolled="listView_Scrolled" IsPullToRefreshEnabled="False"/>
</Grid>

Page.cs

...
private Animation _lastRowAnimation;
private readonly double _initialLastRowHeight;
private readonly RowDefinition _lastRowDefinition;
private bool _isScrolled;
private bool _isFirstRun;
public List<string> Items { get; set; } = new List<string>();
...
public MyPage()
{
InitializeComponent();
_lastRowDefinition = DashboardBarGrid.RowDefinitions[0];
_initialLastRowHeight = _lastRowDefinition.Height.Value;
_isFirstRun = true;

Items.Add("A");
Items.Add("B");
Items.Add("C");
...
Items.Add("Z");
BindingContext = this;
}
...
private void listView_Scrolled(object sender, ScrolledEventArgs e)
{
var listView = (ListView)sender;
if (e.ScrollY > 50) _isFirstRun = false;
if (_isScrolled && e.ScrollY == 0 && _lastRowDefinition?.Height.Value < _initialLastRowHeight){
listView.IsEnabled = false;
_lastRowAnimation = new Animation((d) => _lastRowDefinition.Height = new GridLength(d.Clamp(50, double.MaxValue)), _lastRowDefinition.Height.Value, _initialLastRowHeight, Easing.Linear, () => _lastRowAnimation = null);
_lastRowAnimation.Commit(this, "Animation", 16, 500, Easing.Linear, (v, c) =>
{
_isScrolled = false;
listView.IsEnabled = true;
});
}

// Hide the rows
else if (!_isScrolled && _lastRowDefinition?.Height.Value >= 
_initialLastRowHeight && !_isFirstRun)
{
listView.IsEnabled = false;
_lastRowAnimation = new Animation((d) => _lastRowDefinition.Height = new GridLength(d.Clamp(0, double.MaxValue)), _initialLastRowHeight, 0, Easing.Linear, () => _lastRowAnimation = null);
_lastRowAnimation.Commit(this, "Animation", 16, 500, Easing.Linear, (v, c) =>    {
_isScrolled = true;
listView.IsEnabled = true;
});
}
}

您的原始代码是正确的。一段时间前,我花了一些时间才让它工作起来,但这是我使用的代码。它比MyScrollView类简单得多。

private void TheScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
if (TheScrollView.ScrollY >= TheScrollView.ContentSize.Height - TheScrollView.Height)
{
//All the way to the bottom.
}
else if (TheScrollView.ScrollX <= 0)
{
//All the way to the top.
}
else
{
//Neither all the way to the top nor to the right.
}
}

正如我在问题中提到的,我在ListView中使用ItemAppearing事件实现了相同的功能。但在这种情况下,我的数据是另一个列表中的项目列表。这就是为什么我不得不使用Expander组件在UI上显示数据。

同时,当Expander底部到达时,我需要加载更多的项目。但是Expander没有提供相关的事件,因为它不是一个可滚动的控件。因此,我尝试为ScrollView组件查找一个事件。但也没有运气。

最后,我决定将数据从另一个列表中的一个列表更改为一个列表。我已经使用一些for循环转换了它,现在数据适合ListView。并且我已经使用ItemAppearing事件实现了loadmore特性。

感谢

最新更新