RecyclerView异常问题:返回页面后自动定位至最后一项
嘿,看了你的问题和日志输出,我明白你现在的困扰:首次打开Activity时RecyclerView正常显示第一项,但返回页面后它却自动滚到最后一项,你需要让它始终默认定位到第一项。结合你用的是MvvmCross的MvxRecyclerView,我整理了几个可行的解决思路,你可以逐个尝试:
1. 禁用系统自动恢复滚动位置
Android默认会帮RecyclerView保存和恢复滚动状态,但有时候这个机制会和我们的预期冲突。你可以通过两种方式关掉它:
方式一:布局里直接加属性
在MvxRecyclerView的布局代码中添加android:saveEnabled="false",阻止系统保存滚动位置:
<MvxRecyclerView android:clipToPadding="false" android:id="@+id/myRecyclerView" android:focusable="false" android:layout_height="match_parent" android:layout_width="match_parent" android:scrollbars="vertical" android:saveEnabled="false" />
方式二:手动强制滚动到第一项
在Activity的OnResume方法里,主动让RecyclerView滚到第一项。这样不管系统有没有恢复状态,都能确保显示第一项:
protected override void OnResume() { base.OnResume(); // 直接滚动到第一项,无动画 _recyclerView?.ScrollToPosition(0); // 如果需要平滑滚动,可以用下面这句 // _recyclerView?.SmoothScrollToPosition(0); }
要是你是通过MvvmCross绑定更新数据,最好等数据加载完成后再调用滚动方法,比如监听ViewModel的集合变化事件,等数据准备好再触发滚动。
2. 排查数据集合的更新逻辑
从你的日志能看到,返回页面后GetItemViewType调用了更高的position值(比如6、7),这大概率是数据集合在页面返回时重新加载了,导致RecyclerView重新布局后自动滚到最后。你可以这么调整:
- 尽量复用ViewModel里的数据集合,比如用
ObservableCollection的Clear+AddRange更新内容,而不是每次返回都new一个新集合。这样RecyclerView不会因为集合实例变化而重新计算整个布局。 - 如果必须重新加载数据,就在数据绑定完成后手动调用滚动:
比如在ViewModel的加载完成事件里触发:// 假设你的ViewModel有个DataLoaded事件 ((MyViewModel)ViewModel).DataLoaded += (sender, args) => { _recyclerView?.ScrollToPosition(0); };
3. 解决焦点导致的自动滚动
虽然你给RecyclerView设置了android:focusable="false",但子项里如果有可获取焦点的控件(比如Button、EditText),Android会自动滚动到有焦点的子项。你可以让子项的根布局抢占焦点:
在子项布局的根View里添加这两个属性:
<!-- 子项布局的根容器 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true"> <!-- 子项的内容控件 --> </LinearLayout>
这样根布局会优先获取焦点,避免子项的焦点导致RecyclerView自动滚动。
4. 检查MvxRecyclerView的绑定设置
MvvmCross的MvxRecyclerView有自己的绑定逻辑,你要确保没开启自动滚动到末尾的设置:
- 检查布局里有没有加
local:MvxScrollToEnd="True"这类绑定,有的话删掉它。 - 如果是通过
ItemsSource绑定数据,在绑定完成后主动调用滚动:_recyclerView.ItemsSource = ViewModel.MyItems; _recyclerView.ScrollToPosition(0);
5. 验证Adapter的HasStableIds设置
你在Adapter里设置了HasStableIds = true,这个设置是让RecyclerView通过ItemId复用ViewHolder,但如果GetItemId返回的Id不稳定或者重复,可能导致布局计算异常。你可以先注释掉这个设置,看看问题是否消失:
// 先注释掉测试,看是不是这个导致的问题 // HasStableIds = true;
如果问题解决了,那就要检查fi.Id是否是唯一且稳定的,确保每个Item的Id在页面返回后不会变化。
内容的提问来源于stack exchange,提问作者jmlg

