Я изучал Recyclerview и Cardview и наткнулся на одну проблему, с которой не знаю, как с ней справиться. Мой recyclerview работает нормально, но когда я заставляю фон элемента recyclerview менять цвет при нажатии, он ведет себя странно.
Итак, recyclerview загружается нормально, однако, когда я впервые нажимаю на элемент, цвет фона элемента мерцает своим новым цветом, но затем остается цветом по умолчанию. Когда я нажимаю на любой элемент во второй раз, только тогда элемент recyclerview меняет свой цвет фона, как и предполагалось, вместе с остальной частью щелкнутого элемента.
Из Log.d, который я добавил в свой код, я обнаружил, что то, что отличается первый щелчок от второго (и остальных) щелчка, является общедоступным PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) в классе PremiseAdapter. Я нашел вопрос, похожий на мою проблему, но я не думаю, что мой код работает таким образом.
Журналы, как показано ниже.
.... D/rcvTest: PremiseAdapter.PremiseAdapter
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: FroyYo Mart
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM FroyYo Mart
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: Ice Cream Store
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM Ice Cream Store
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: [ViewHolder].ViewHolder.listener: null
.... D/rcvTest: [ViewHolder].ViewHolder.getAdapterPosition(): 1
.... D/rcvTest: [ViewHolder].ViewHolder.position: 1
.... D/rcvTest: getLayoutPosition(): 1
.... D/rcvTest: [ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: Ice Cream Store
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM Ice Cream Store
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: [ViewHolder].ViewHolder.listener: null
.... D/rcvTest: [ViewHolder].ViewHolder.getAdapterPosition(): 0
.... D/rcvTest: [ViewHolder].ViewHolder.position: 0
.... D/rcvTest: getLayoutPosition(): 0
.... D/rcvTest: [ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: FroyYo Mart
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM FroyYo Mart
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: PremiseAdapter.getItemCount
А это мой PremiseAdapter.java файл, который содержит мой PremiseAdapter класс и ViewHolder класс.
public class PremiseAdapter extends RecyclerView.Adapter<PremiseAdapter.ViewHolder> {
private ArrayList<Premise> mPremiseData;
private Context context;
private int selected_position = -1;
OnItemClickListener onItemClickListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener itemClickListener) {
onItemClickListener = itemClickListener;
}
public PremiseAdapter(Context context, ArrayList<Premise> mPremiseData) {
Log.d("rcvTest", "PremiseAdapter.PremiseAdapter");
this.mPremiseData = mPremiseData;
this.context = context;
}
//Required method for creating the viewholder objects.
@NonNull
@Override
public PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d("rcvTest", "---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder");
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_premises, parent, false), onItemClickListener);
}
//Required method that binds the data to the viewholder.
@Override
public void onBindViewHolder(@NonNull PremiseAdapter.ViewHolder holder, int position) {
// Get current premise.
// Populate the textviews with data.
}
@Override
public int getItemCount() {
Log.d("rcvTest", "PremiseAdapter.getItemCount");
return mPremiseData.size();
}
/*----------------------------------- CLASS VIEWHOLDER -------------------------------------------*/
/*----------------------------------- CLASS VIEWHOLDER -------------------------------------------*/
/*class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {*/
class ViewHolder extends RecyclerView.ViewHolder {
// Member Variables for the TextViews
//Constructor for the ViewHolder, used in onCreateViewHolder().
ViewHolder(@NonNull View itemView, OnItemClickListener listener) {
super(itemView);
cardView = itemView.findViewById(R.id.cardview_premise);
Log.d("rcvTest", "[ViewHolder].ViewHolder.TOP");
// Initialize the views.
// Set the OnClickListener to the entire view.
int clickedColor = Color.parseColor("#D5F5E3");
itemView.setOnClickListener((v) -> {
int position = getAdapterPosition();
Log.d("rcvTest", "[ViewHolder].ViewHolder.listener: " + listener);
Log.d("rcvTest", "[ViewHolder].ViewHolder.getAdapterPosition(): " + getAdapterPosition());
Log.d("rcvTest", "[ViewHolder].ViewHolder.position: " + position);
Log.d("rcvTest", "getLayoutPosition(): " + getLayoutPosition());
if (position != RecyclerView.NO_POSITION) {
Log.d("rcvTest", "[ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
} else if (position == RecyclerView.NO_POSITION) {
Log.d("rcvTest", "[ViewHolder].ViewHolder.position == RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
}
notifyItemChanged(position);
notifyItemChanged(getLayoutPosition());
});
}
void bindTo(Premise currentPremise) {
// Populate the textviews with data.
Log.d("rcvTest", "[ViewHolder].bindTo.TOP: " + currentPremise.getPremiseName());
}
}
}
Попробуйте это. Недавно у меня был этот код, и он отлично работает, надеюсь, он решит и вашу проблему.
int row_index = -1;
holder.itemView.setOnClickListener(v -> {
row_index = position;
notifyDataSetChanged();
});
if (row_index == position) {
holder.layout.setBackgroundColor(Color.parseColor("#ff6600"));
} else {
holder.layout.setBackgroundColor(Color.parseColor("#ffffff"));
}
Спасибо Прайсу Али за объяснение кода для него. извините за поздний ответ, Али объяснил вам правильно.
@AtresJuni row_index — это переменная глобуса, и добавьте оставшийся код в onBindViewHolder. (holder.layout) — это корневой макет, в который вы хотите добавить цвет фона.
это работает! Я изменил notifyDataSetChanged(); на notifyItemChanged(position);, чтобы цвет оставался прежним, когда я нажимаю на другой элемент. Но почему это все же?
хорошо знать. Так что вы можете принять ответ сейчас.
хорошо конечно! но перед этим, можете ли вы объяснить, почему notifyDataSetChanged() результат отличается от notifyItemChanged(position) @ahmadbajwa
Поскольку notifyDataSetChanged() уведомляет весь набор данных, а notifyItemChanged(position) уведомляет только данный элемент. Это похоже на обновление одного индекса и всего списка.
Если вы просто обновляете одну часть представления, используйте notifyItemRangeChanged() или notifyItemChanged() вместо notifiyDataSetChanged(). Разница здесь связана со структурными изменениями и изменениями предметов.
@AtresJuni хорошо, спасибо, но вы все равно не приняли ответ.
Обычно я реализую прослушиватели onclick в onbindviewholder, и они, кажется, работают нормально. Я бы посоветовал вам попробовать это.
Переместите этот фрагмент кода в onbindviewholder
int clickedColor = Color.parseColor("#D5F5E3");
/*itemView.setBackgroundColor(defaultColor);*/
holder.itemView.setOnClickListener((v) -> {
int position = getAdapterPosition();
Log.d("rcvTest", "[ViewHolder].ViewHolder.listener: " + listener);
Log.d("rcvTest", "[ViewHolder].ViewHolder.getAdapterPosition(): " + getAdapterPosition());
Log.d("rcvTest", "[ViewHolder].ViewHolder.position: " + position);
Log.d("rcvTest", "getLayoutPosition(): " + getLayoutPosition());
if (position != RecyclerView.NO_POSITION) {
Log.d("rcvTest", "[ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION");
/*listener.onItemClick(position);*/
itemView.setBackgroundColor(clickedColor);
} else if (position == RecyclerView.NO_POSITION) {
Log.d("rcvTest", "[ViewHolder].ViewHolder.position == RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
}
notifyItemChanged(position);
position = getLayoutPosition();
notifyItemChanged(position); //duplicate
});
Просто не забудьте изменить
itemView.setOnClickListener(...) to holder.itemView.setOnClickListener(...)
Измените его на holder.itemView, чтобы быть конкретным.
@PrinceAli, да, конечно
спасибо за ответ. Могу ли я узнать, где мне это реализовать? Аналогичный код, который у меня есть, хранится в
ViewHolder(@NonNull View itemView, OnItemClickListener listener)в классеViewHolder, но у меня в нем нетholder.