2017-03-18 52 views
0

我有以下代码为例。回收站的奇怪行为

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

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中

<?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

<?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> 

它的工作这么好,是正确的。当我滚动浏览列表时,我会在日志中逐个接收来自Adapter的消息:“onBindViewHolder:”+位置。但接下来我的问题。当我尝试在RecyclerView之上添加一些视图时,如下面的代码所示。适配器同时显示方法onBindViewHolder的所有调用。在下一个代码中将RecyclerView包装在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.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> 

回答

2

RecyclerView是一个ListView。它只会显示您当前可以看到的项目,在您滚动时重新使用部件。

现在,您将RecyclerView包装在LinearLayout内的NestedScrollView内,会发生什么情况?

A NestedScrollView需要知道大小LinearLayout来处理滚动。
LinearLayout如何知道它应该是多长时间,而不知道RecyclerViews的总长度? 它没有。

所以recyclerView得到完全充气,一次所有的意见,都在一条长长的线。没有回收,没有重复使用。这是你遇到的现象。
现在LinearLayout能够正确说出NestedScrollView它的高度(TextView的总高度和的RecyclerView的所有项目)和NestedScrollView可以处理滚动。


这就是为什么嵌套的滚动是总是一个坏主意。如果可能,请尝试将TextView作为项目转换为的RecyclerView并摆脱包装NestedScrollview
例如如下所示:Is there an addHeaderView equivalent for RecyclerView?

另一种选择是从滚动视图中删除recyclerview并将其放在下面。不过,标题不会滚动。

+0

什么解释。 – MadScientist

+0

这真的很累 – Mike

+0

我按照所说的添加了标题,一切正常,但我的最后一项并不完全适合RecyclerVIew。最后一项在标题的高度上裁剪, – Mike

0

除非你有一个很好的理由在您的层次结构中的NestedScrollView,你可以实现在上面一个TextView下面只此布局代码RecyclerView :

<?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>