【发布时间】:2016-07-18 19:27:51
【问题描述】:
当我在 NestedScrollView 中添加 RecyclerView 时,出现奇怪的滚动行为。
发生的情况是,每当滚动视图的行数超过屏幕上显示的行数时,一旦启动 Activity,NestedScrollView 就会从顶部偏移开始(图 1)。如果滚动视图中的项目很少,因此它们都可以一次显示,则不会发生这种情况(图 2)。
我正在使用 23.2.0 版的支持库。
图片 1:错误 - 从顶部偏移开始
图片 2:正确 - 回收站视图中的一些项目
我在我的布局代码下面粘贴:
<?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>
我错过了什么吗?有谁知道如何解决这个问题?
更新 1
如果我在初始化我的 Activity 时放置以下代码,它可以正常工作:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
其中 sv 是对 NestedScrollView 的引用,但它看起来像个 hack。
更新 2
根据要求,这是我的适配器代码:
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:
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 - 此屏幕仅用于显示此错误的示例):
<?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"/>
【问题讨论】:
-
用
android:focusableInTouchMode="false"尝试RecyclerView? smth 显然是“强制你的布局到底部......(当你有 1295 个项目时它从哪里开始?底部或只是像第一个屏幕一样的小顶部偏移) -
将 android:clipToPadding="true" 设置为 NestedScrollView 。
-
另外:将可滚动视图保持在另一个同向可滚动视图中并不是很好的模式...希望您使用正确的
LayoutManager -
尝试了您的两个建议,但不幸的是都没有奏效。 @snachmsm 无论回收器视图中的项目数量如何,偏移量始终相同。至于在 NestedScrollView 中放置 RecyclerView 是否是一个好的模式,这个其实已经被 Google 工程师推荐了plus.google.com/u/0/+AndroidDevelopers/posts/9kZ3SsXdT2T
-
即使我在 NestedScrollView 中使用 RecyclerView 时也遇到了同样的问题。这是一个糟糕的模式,因为回收器模式本身不起作用。所有视图将一次绘制(因为 WRAP_CONTENT 需要回收器视图的高度)。后台不会有任何视图回收,所以回收器视图本身的主要目的是不起作用的。但是使用recycler view很容易管理数据和绘制布局,这是你可以使用这种模式的唯一原因。所以最好不要使用它,除非你确实需要它。
标签: android android-support-library android-recyclerview android-nestedscrollview