You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中如何避免CollectionView重置滚动位置至起始处

在.NET MAUI中解决CollectionView赋值ItemsSource时滚动位置重置的问题

一、避免滚动位置重置的最优方案

不要直接替换ItemsSource的引用,而是复用原有ObservableCollection并修改其内容:

  • 初始化时将ItemsSource绑定到一个ObservableCollection<T>实例
  • 搜索或更新数据时,先清空集合,再批量添加过滤后的项(可扩展ObservableCollection实现AddRange方法,原生无此方法)

示例代码:

// 扩展ObservableCollection的AddRange方法
public static class ObservableCollectionExtensions
{
    public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
}

// 使用示例
private ObservableCollection<YourModel> _originalItems;
private ObservableCollection<YourModel> _displayItems;

// 初始化
_displayItems = new ObservableCollection<YourModel>();
collectionView.ItemsSource = _displayItems;
_originalItems = GetOriginalData(); // 获取原始数据集合

// 搜索逻辑
private void OnSearchTextChanged(string searchText)
{
    var filteredItems = _originalItems.Where(item => item.Name.Contains(searchText)).ToList();
    _displayItems.Clear();
    _displayItems.AddRange(filteredItems);
}

这种方式未替换ItemsSource引用,CollectionView仅更新项内容,不会重置滚动位置。

二、获取并恢复CollectionView的滚动位置

若必须替换ItemsSource,需先保存当前滚动位置,赋值后手动恢复。由于.NET MAUI原生未直接提供滚动位置属性,需通过平台特定Handler实现:

1. 保存当前滚动位置

针对不同平台获取滚动偏移量:

private double _scrollOffset;

private void SaveScrollPosition()
{
#if ANDROID
    var recyclerView = collectionView.Handler.PlatformView as AndroidX.RecyclerView.RecyclerView;
    if (recyclerView != null)
    {
        var layoutManager = recyclerView.GetLayoutManager() as AndroidX.RecyclerView.LinearLayoutManager;
        _scrollOffset = layoutManager.FindFirstVisibleItemPosition();
        // 如需精确像素偏移,可获取第一个可见项的顶部距离
        // var firstVisibleView = layoutManager.FindViewByPosition(layoutManager.FindFirstVisibleItemPosition());
        // _scrollOffset = -firstVisibleView.Top;
    }
#elif IOS
    var collectionView = collectionView.Handler.PlatformView as UIKit.UICollectionView;
    if (collectionView != null)
    {
        _scrollOffset = collectionView.ContentOffset.Y;
    }
#endif
}

2. 恢复滚动位置

重新赋值ItemsSource后,调用ScrollTo方法恢复位置:

private void RestoreScrollPosition()
{
    if (_scrollOffset >= 0)
    {
#if ANDROID
        collectionView.ScrollTo((int)_scrollOffset, position: ScrollToPosition.Start, animate: false);
#elif IOS
        var targetItem = _displayItems[(int)(_scrollOffset / collectionView.ItemHeight)];
        collectionView.ScrollTo(targetItem, position: ScrollToPosition.Start, animate: false);
#endif
    }
}

使用流程

// 重新赋值前保存位置
SaveScrollPosition();
// 替换ItemsSource
collectionView.ItemsSource = newFilteredCollection;
// 恢复位置
RestoreScrollPosition();

注意事项

  • Android平台用FindFirstVisibleItemPosition获取可见项索引,适合多数场景;如需像素级精度,需额外计算可见项顶部距离。
  • iOS平台可直接获取ContentOffset.Y,再根据项高度转换为索引,或通过Handler直接设置原生控件的ContentOffset。

内容的提问来源于stack exchange,提问作者Sh.sh94

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:42:15