Recyclerview中的多个视图被更改而不是仅一个视图

时间:2018-05-28 06:56:15

标签: android android-recyclerview recycler-adapter

我创建了一个带有Recyclerview的应用程序,每个项目都有Textview和Button。最初,所有Textviews都将是不可见的。我希望在按下相应的按钮时可以看到它。我设法做到这一点,但它有一个问题。

这是我的代码的简化版本:

MainActivity.java

package com.example.so;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private WordListAdapter mAdapter;

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

        mRecyclerView = findViewById(R.id.recyclerview);
        mAdapter = new WordListAdapter(this);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    }

}

WordListAdapter.java

package com.example.so;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

public class WordListAdapter extends RecyclerView.Adapter<WordListAdapter.WordViewHolder> {
    private LayoutInflater mInflator;

    public WordListAdapter(Context context) {
        mInflator = LayoutInflater.from(context);
    }

    class WordViewHolder extends RecyclerView.ViewHolder {
        private final TextView itemTextview;
        private final Button itembutton;
        final WordListAdapter mAdapter;

        public WordViewHolder(View itemView, WordListAdapter adapter) {
            super(itemView);
            itemTextview = itemView.findViewById(R.id.item_text);
            itembutton = itemView.findViewById(R.id.item_button);
            this.mAdapter = adapter;

            itembutton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    itemTextview.setVisibility(View.VISIBLE);
                }
            });

        }
    }


    @NonNull
    @Override
    public WordListAdapter.WordViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View mItemView = mInflator.inflate(R.layout.wordlist_item, parent, false);
        return new WordViewHolder(mItemView, this);
    }

    @Override
    public void onBindViewHolder(@NonNull WordListAdapter.WordViewHolder holder, int position) {
    }

    @Override
    public int getItemCount() {
        return 20;
    }
}

wordlist_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="50dp"
    android:orientation="horizontal"
    android:layout_margin="6dp">

    <TextView
        android:id="@+id/item_text"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:gravity="center"
        android:layout_weight="1"
        android:text="Button clicked!"
        android:visibility="invisible"/>

    <Button
        android:id="@+id/item_button"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

问题在于,当我按下第一个按钮时,除了第一个Textview之外,第15个Textview变得可见。同样,当我按下第16个按钮时,第2个Textview,除了 第16个Textview变得可见。其他按钮也是如此。

我不确定为什么按下单个按钮时两个Textview会变得可见。代码有什么问题?

6 个答案:

答案 0 :(得分:1)

滚动并向您展示新的RecyclerView项目时,会使用 onBindViewHolder()函数重新绘制(再循环)数据并将数据新插入其中。

我建议您使用 onBindViewHolder()中的集合数组,并使用 onBindViewHolder()中的一些逻辑隐藏或显示它们。

构造函数

private boolean[] visibleItems;

public WordListAdapter(Context context) {
    mInflator = LayoutInflater.from(context);
    visibleItems = new boolean[20];
}

ViewHolder

itembutton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) { 
            int pos = getAdapterPosition();
            visibleItems[pos] = true;
            notifyItemChanged(pos);
        }
    });

onBindViewHolder()

@Override
public void onBindViewHolder(@NonNull WordListAdapter.WordViewHolder holder, int position) {
    if(visibleItems[position]) 
        itemTextview.setVisibility(View.VISIBLE);
    else itemTextview.setVisibility(View.INVISIBLE);
}

如果RecyclerView项目中存在EditTexts并且未在同一函数内使用 setText()设置它们,则会出现同样的问题,但只能编辑。

答案 1 :(得分:1)

当您在回收站视图中滚动时,这些项目会被回收。因此,创建一个变量来存储您单击该按钮的项目的位置。

@Override public void onBindViewHolder(@NonNull WordListAdapter.WordViewHolder holder, final int position){ holder.itemTextview.setVisibility(View.INVISIBLE); if(currentPosition == position){ holder.itemTextview.setVisibility(View.VISIBLE); } holder.itembutton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View p1){ // TODO: Implement this method currentPosition = position; notifyDataSetChanged(); } }); }

中实施
WordListAdapter

班级public class WordListAdapter extends RecyclerView.Adapter<WordListAdapter.WordViewHolder> { private Context context; private static int currentPosition=0; public WordListAdapter(Context context){ this.context = context; } class WordViewHolder extends RecyclerView.ViewHolder { private final TextView itemTextview; private final Button itembutton; public WordViewHolder(View itemView){ super(itemView); itemTextview = (TextView)itemView.findViewById(R.id.item_text); itembutton = (Button) itemView.findViewById(R.id.item_button); } } @NonNull @Override public WordListAdapter.WordViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ View mItemView = LayoutInflater.from(context).inflate(R.layout.wordlist_item, parent, false); return new WordViewHolder(mItemView); } @Override public void onBindViewHolder(@NonNull WordListAdapter.WordViewHolder holder, final int position){ holder.itemTextview.setVisibility(View.INVISIBLE); if(currentPosition == position){ holder.itemTextview.setVisibility(View.VISIBLE); } holder.itembutton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View p1){ // TODO: Implement this method currentPosition = position; notifyDataSetChanged(); } }); } @Override public int getItemCount(){ return 20; } } 将如下所示。

{{1}}

答案 2 :(得分:0)

尝试在适配器中实现getItemId()方法。

 @Override
    public long getItemId(int position) {
        return position;
    }

答案 3 :(得分:0)

您应为每个项目指定可见/隐藏状态。并在单击按钮时更改状态。

在onBindViewHolder()中你应该使用if / else来使TextView可见/消失。像下面的东西。 data是您商品的数组。 VisibilityStatus是我上面提到的状态。您可以将其放在数据模型中,也可以将其保存在另一个数组或SparseBooleanArray

if (data.getVisibilityStatus(position)) {
    itemTextview.setVisibility(View.VISIBLE);
} else {
    itemTextview.setVisibility(View.GONE);
}

答案 4 :(得分:0)

您需要在适配器中添加此方法 此方法返回项目的视图类型,以便进行视图回收。

@Override
public int getItemViewType(int position) {
    return position;
}

在适配器中

public class WordListAdapter extends RecyclerView.Adapter<WordListAdapter.WordViewHolder> {
    private LayoutInflater mInflator;

    public WordListAdapter(Context context) {
        mInflator = LayoutInflater.from(context);
    }

    class WordViewHolder extends RecyclerView.ViewHolder {
        private TextView itemTextview;
        private Button itembutton;
//        final WordListAdapter mAdapter;

        public WordViewHolder(View itemView) {
            super(itemView);
            itemTextview = itemView.findViewById(R.id.item_text);
            itembutton = itemView.findViewById(R.id.item_button);
        }
    }


    @NonNull
    @Override
    public WordListAdapter.WordViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View mItemView = mInflator.inflate(R.layout.wordlist_item, parent, false);
        return new WordViewHolder(mItemView);
    }

    @Override
    public void onBindViewHolder(@NonNull final WordListAdapter.WordViewHolder holder, int position) {
        holder.itembutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                holder.itemTextview.setVisibility(View.VISIBLE);
            }
        });
    }

    @Override
    public int getItemCount() {
        return 20;
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }
}

答案 5 :(得分:0)

扩展为Viktor Stojanov's回答:

此行为是由于recyclerView的属性为“回收”的视图。

当滚动列表时,变为不可见的视图可以重新使用,并且这些视图将再次用于即将在屏幕上显示的项目。 即使用相同的上部视图,只使用 onBindViewHolder()绑定新数据。

我建议您维护一个简单POJO的Arraylist并引用它们的状态来更新recyclerView中的视图。 e.g。

public class Word{
     private boolean isVisible;
     private String content;

     //getters and setters for both properties
}

在bindViewHolder中检查item的可见性,并相应地显示textView。

@Override
public void onBindViewHolder(@NonNull WordListAdapter.WordViewHolder holder, int position) {
    Word currentWord = wordArraylist.get(position);
    if(currentWord.getVisibility()){
        itemTextView.setText(currentWord.getContent());
        itemTextview.setVisibility(View.VISIBLE);
    } else{
        if(itemTextView.getVisibility != View.INVISIBLE){
           itemTextview.setVisibility(View.INVISIBLE);
        }
    }
}

在您的ViewHolder类中,您可以在按钮上设置onClickListener以更改可见性,如下所示:

    itembutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { 
                Word currentWord = wordArraylist.get(getAdapterPosition());
                if(!currentWord.getVisibility()){
                     itemTextView.setText(currentWord.getContent());
                     itemTextview.setVisibility(View.VISIBLE);
                }
            }
});