问题描述
当我在NestedScrollView中添加RecyclerView时,出现了奇怪的滚动行为.
I am getting a weird scrolling behavior when I add a RecyclerView inside a NestedScrollView.
发生的事情是,每当滚动视图的行数超过屏幕显示的行数时,活动启动后,NestedScrollView就会从顶部开始偏移(图1).如果滚动视图中的项目很少,因此可以一次显示所有项目,则不会发生(图像2).
What happens is that whenever the scrollview has more rows than can be shown in the screen, as soon as the activity is launched, the NestedScrollView starts with an offset from the top (image 1). If there are few items in the scroll view so that they can all be shown at once, this doesn't happen (image 2).
我正在使用支持库的23.2.0版本.
I am using version 23.2.0 of the support library.
图片1 :错误-从顶部偏移开始
Image 1: WRONG - starts with offset from the top
图片2 :正确-回收者视图中的物品很少
Image 2: CORRECT - few items in the recycler view
我要粘贴以下布局代码:
I am pasting below my layout code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
style="@style/TextAppearance.AppCompat.Body1"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Body1"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我错过了什么吗?有谁知道如何解决这个问题?
Am I missing something? Does anyone have any idea how to fix this?
更新1
如果在初始化我的活动时放置以下代码,它将正常工作:
It works correctly if I place the following code when initializing my Activity:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
其中sv是对NestedScrollView的引用,但是看起来很hack.
Where sv is a reference to the NestedScrollView, however it looks like quite a hack.
更新2
根据要求,这是我的适配器代码:
As requested, here is my adapter code:
public abstract class ArrayAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private List<T> mObjects;
public ArrayAdapter(final List<T> objects) {
mObjects = objects;
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(final T object) {
mObjects.add(object);
notifyItemInserted(getItemCount() - 1);
}
/**
* Remove all elements from the list.
*/
public void clear() {
final int size = getItemCount();
mObjects.clear();
notifyItemRangeRemoved(0, size);
}
@Override
public int getItemCount() {
return mObjects.size();
}
public T getItem(final int position) {
return mObjects.get(position);
}
public long getItemId(final int position) {
return position;
}
/**
* Returns the position of the specified item in the array.
*
* @param item The item to retrieve the position of.
* @return The position of the specified item.
*/
public int getPosition(final T item) {
return mObjects.indexOf(item);
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(final T object, int index) {
mObjects.add(index, object);
notifyItemInserted(index);
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(T object) {
final int position = getPosition(object);
mObjects.remove(object);
notifyItemRemoved(position);
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
Collections.sort(mObjects, comparator);
notifyItemRangeChanged(0, getItemCount());
}
}
这是我的ViewHolder:
And here is my ViewHolder:
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView txt;
public ViewHolder(View itemView) {
super(itemView);
txt = (TextView) itemView;
}
public void render(String text) {
txt.setText(text);
}
}
这是RecyclerView中每个项目的布局(仅为android.R.layout.simple_spinner_item
-此屏幕仅用于显示此bug的示例):
And here is the layout of each item in the RecyclerView (it's just android.R.layout.simple_spinner_item
- this screen is only for showing an example of this bug):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>
推荐答案
我通过以下方法解决了此类问题:
I solved such issue by setting:
<ImageView ...
android:focusableInTouchMode="true"/>
回到我在RecyclerView上方的视图(在不必要的滚动后被隐藏了).尝试将此属性设置为RecyclerView上方的LinearLayout或RecyclerView的容器LinearLayout(在另一种情况下对我有帮助).
to my view above RecyclerView (which was hidden after unwanted scroll). Try to set this property to your LinearLayout above RecyclerView or to LinearLayout which is container of RecyclerView (helped me in another case).
正如我在NestedScrollView源代码中看到的那样,它尝试将焦点集中在onRequestFocusInDescendants中的第一个可能的子对象上,如果只有RecyclerView是可聚焦的,它将获胜.
As I see in NestedScrollView source it tries to focus the first possible child in onRequestFocusInDescendants and if only RecyclerView is focusable it wins.
编辑(感谢Waran):为了流畅滚动,请不要忘记设置yourRecyclerView.setNestedScrollingEnabled(false);
Edit (thanks to Waran): and for smooth scroll don't forget to set yourRecyclerView.setNestedScrollingEnabled(false);
这篇关于NestedScrollView中的Recycler视图导致滚动从中间开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!