简体   繁体   English

RecyclerView的奇怪行为

[英]Strange behavior of the RecyclerView

I have the following code for example. 我有以下代码为例。

MainActivity.java MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        List<String> names = new ArrayList<>();
        names.add("one");
        names.add("two");
        names.add("three");
        names.add("four");
        names.add("five");
        names.add("six");
        names.add("seven");
        names.add("eight");
        names.add("nine");
        names.add("ten");

        RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        rv.setLayoutManager(llm);

        RvAdapter adapter = new RvAdapter(names);
        rv.setAdapter(adapter);
    }
}

RvAdapter.java RvAdapter.java

public class RvAdapter extends RecyclerView.Adapter<RvAdapter.PersonViewHolder> {
    public static final String TAG = RvAdapter.class.getSimpleName();
    List<String> persons;

    RvAdapter(List<String> persons) {
        this.persons = persons;
    }

    @Override
    public RvAdapter.PersonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        return new PersonViewHolder(v);
    }

    @Override
    public void onBindViewHolder(RvAdapter.PersonViewHolder holder, int position) {
        holder.name.setText(persons.get(position));
        Log.d(TAG, "onBindViewHolder: " + position);
    }

    @Override
    public int getItemCount() {
        return persons.size();
    }

    public static class PersonViewHolder extends RecyclerView.ViewHolder {
        CardView cv;
        TextView name;

        PersonViewHolder(View itemView) {
            super(itemView);
            cv = (CardView) itemView.findViewById(R.id.cv);
            name = (TextView) itemView.findViewById(R.id.name);

        }
    }
}

activity_main.xml activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mrmayhem.myapplication.MainActivity">
            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

            </android.support.v7.widget.RecyclerView>
</RelativeLayout>

item.xml item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp">

    <android.support.v7.widget.CardView
        android:id="@+id/cv"
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </android.support.v7.widget.CardView>
</LinearLayout>

It works so good and correct. 它是如此的好和正确。 When I scroll through the list I get successive messages from Adapter one by one in Logs: "onBindViewHolder: " + position. 当我滚动列表时,在日志中依次从适配器获得连续的消息:“ onBindViewHolder:” +位置。 But my problem in next. 但是我接下来的问题。 When i try add some View above the RecyclerView , as shown in the code below. 当我尝试在RecyclerView上方添加一些View时,如下面的代码所示。 Adapter displays all calls of the method onBindViewHolder simultaneously . 适配器的显示器的方法的所有调用onBindViewHolder 同时 Wrap the RecyclerView in activity_main.xml by the next code. 通过下一个代码将RecyclerView包裹在activity_main.xml中

activity_main.xml (with header) activity_main.xml(带标题)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mrmayhem.myapplication.MainActivity">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="HEADER" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

            </android.support.v7.widget.RecyclerView>
        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

</RelativeLayout>

RecyclerView is a ListView. RecyclerView是一个ListView。 It will only display the items that you can currently see, reusing parts as you scroll. 它将仅显示您当前可以看到的项目,并在滚动时重复使用零件。

Now you wrap the RecyclerView in a LinearLayout within a NestedScrollView , what happens? 现在,将RecyclerView包装在NestedScrollView内的LinearLayout中,会发生什么情况?

A NestedScrollView needs to know the size of the LinearLayout to handle the scrolling. NestedScrollView需要知道LinearLayout大小才能处理滚动。
How does the LinearLayout know how long it should be, without knowing the RecyclerViews total length? LinearLayout如何在不知道RecyclerViews总长度的情况下知道应该多长? It doesn't. 没有。

So the recyclerView gets completely inflated, all views at once, all in a long line. 因此,recyclerView会完全膨胀,所有视图一次排成一行。 No recycling, no reuse. 不回收,不重复使用。 This is the phenomenon you experience. 这就是您遇到的现象。
Now the LinearLayout can properly tell the NestedScrollView it's height (the total height of the TextView and all the items of the RecyclerView) and the NestedScrollView can handle the scrolling. 现在, LinearLayout可以正确告知NestedScrollView它的高度(TextView和RecyclerView的所有项目的总高度),而NestedScrollView可以处理滚动。


This is why nested scrolling is always a bad idea. 这就是为什么嵌套滚动始终是一个坏主意的原因。 If possible, try to move your TextView as an item into the RecyclerView and get rid of the wrapping NestedScrollview . 如果可能,请尝试将TextView作为一项移至 RecyclerView中,并摆脱包装的NestedScrollview
eg as seen here: Is there an addHeaderView equivalent for RecyclerView? 例如,如此处所示: RecyclerView是否具有等效的addHeaderView?

Another option would be to remove the recyclerview from the scroll view and put it below. 另一个选择是从滚动视图中删除recyclerview并将其放在下面。 The header would not scroll then, though. 但是,标题将不会滚动。

Unless you have a good reason to have a NestedScrollView in your hierarchy, you could achieve a TextView on top with a RecyclerView below with just this layout code: 除非您有充分的理由在您的层次结构中使用NestedScrollView ,否则可以使用以下布局代码在顶部使用下面的RecyclerView来实现TextView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.mrmayhem.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="HEADER" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</LinearLayout>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM