Почему элемент RecyclerView меняет цвет фона только после двойного щелчка по нему?

Я изучал Recyclerview и Cardview и наткнулся на одну проблему, с которой не знаю, как с ней справиться. Мой recyclerview работает нормально, но когда я заставляю фон элемента recyclerview менять цвет при нажатии, он ведет себя странно.

Итак, recyclerview загружается нормально, однако, когда я впервые нажимаю на элемент, цвет фона элемента мерцает своим новым цветом, но затем остается цветом по умолчанию. Когда я нажимаю на любой элемент во второй раз, только тогда элемент recyclerview меняет свой цвет фона, как и предполагалось, вместе с остальной частью щелкнутого элемента.

Из Log.d, который я добавил в свой код, я обнаружил, что то, что отличается первый щелчок от второго (и остальных) щелчка, является общедоступным PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) в классе PremiseAdapter. Я нашел вопрос, похожий на мою проблему, но я не думаю, что мой код работает таким образом.

Журналы, как показано ниже.

  1. Загружает recyclerview и его элемент Cardview
.... 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)
  1. Сначала нажмите на элемент
.... 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)
  1. Второй (и остальные) щелчок по элементу
.... 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());
        }
    }
}
1
0
661
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Попробуйте это. Недавно у меня был этот код, и он отлично работает, надеюсь, он решит и вашу проблему.

 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"));
        }

спасибо за ответ. Могу ли я узнать, где мне это реализовать? Аналогичный код, который у меня есть, хранится в ViewHolder(@NonNull View itemView, OnItemClickListener listener) в классе ViewHolder, но у меня в нем нет holder.

Atres Juni 23.12.2020 11:44

Спасибо Прайсу Али за объяснение кода для него. извините за поздний ответ, Али объяснил вам правильно.

ahmad bajwa 23.12.2020 12:01

@AtresJuni row_index — это переменная глобуса, и добавьте оставшийся код в onBindViewHolder. (holder.layout) — это корневой макет, в который вы хотите добавить цвет фона.

ahmad bajwa 23.12.2020 12:03

это работает! Я изменил notifyDataSetChanged(); на notifyItemChanged(position);, чтобы цвет оставался прежним, когда я нажимаю на другой элемент. Но почему это все же?

Atres Juni 23.12.2020 13:55

хорошо знать. Так что вы можете принять ответ сейчас.

ahmad bajwa 23.12.2020 14:05

хорошо конечно! но перед этим, можете ли вы объяснить, почему notifyDataSetChanged() результат отличается от notifyItemChanged(position) @ahmadbajwa

Atres Juni 23.12.2020 14:20

Поскольку notifyDataSetChanged() уведомляет весь набор данных, а notifyItemChanged(position) уведомляет только данный элемент. Это похоже на обновление одного индекса и всего списка.

ahmad bajwa 23.12.2020 14:24

Если вы просто обновляете одну часть представления, используйте notifyItemRangeChanged() или notifyItemChanged() вместо notifiyDataSetChanged(). Разница здесь связана со структурными изменениями и изменениями предметов.

ahmad bajwa 23.12.2020 14:26

@AtresJuni хорошо, спасибо, но вы все равно не приняли ответ.

ahmad bajwa 23.12.2020 15:39

Обычно я реализую прослушиватели 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, чтобы быть конкретным.

private static 23.12.2020 12:01

@PrinceAli, да, конечно

Saksham Pruthi 23.12.2020 12:25

Другие вопросы по теме