视图导致滚动从中间开始

视图导致滚动从中间开始

本文介绍了NestedScrollView 中的 Recycler 视图导致滚动从中间开始的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 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

如果我在初始化 Activity 时放置以下代码,它可以正常工作:

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 的引用,但它看起来像一个黑客.

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 - 此屏幕仅用于显示此错误的示例):

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 视图导致滚动从中间开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 03:51