【问题标题】:Why does the RecyclerView item only change background color after clicking on it twice?为什么 RecyclerView 项目在点击两次后才改变背景颜色?
【发布时间】:2021-04-01 23:25:20
【问题描述】:

我一直在探索 Recyclerview 和 Cardview,但偶然发现了一个我不知道如何处理的问题。我的 recyclerview 工作正常,但是当我让 recyclerview 的项目背景在点击时更改颜色时,它的行为很奇怪。

好的,recyclerview 加载正常,但是当我第一次单击某个项目时,项目背景颜色会闪烁其新颜色,但随后会保持其默认颜色。当我第二次单击任何项​​目时,recyclerview 的项目才会更改其背景颜色,因为它应该与单击的其余项目一起。

从我添加到代码中的Log.d 中,我发现第一次点击与第二次(以及其他)点击的不同之处在于PremiseAdapter 类中的公共PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)。我发现了一个与我的问题类似的question,但我认为我的代码不是这样工作的。

日志如下。

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

【问题讨论】:

    标签: android android-recyclerview android-adapter android-cardview android-viewholder


    【解决方案1】:

    我通常在 onbindviewholder 中实现 onclick 侦听器,它们似乎工作正常。我建议你应该尝试一下。
    把这段代码移到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 是的,当然
    【解决方案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 类的ViewHolder(@NonNull View itemView, OnItemClickListener listener) 中,但我没有holder。
    • 感谢 Price Ali 为他解释代码。抱歉,阿里向您解释了迟到的回复。
    • @AtresJuni row_index 是全局变量,并将剩余代码添加到 onBindViewHolder。 (holder.layout) 是要添加背景颜色的根布局。
    • 这行得通!我将notifyDataSetChanged(); 更改为notifyItemChanged(position);,这样当我单击另一个项目时颜色保持不变。但为什么会这样呢?
    • 确定!但在此之前,你能解释一下为什么notifyDataSetChanged() 产生与notifyItemChanged(position) 不同的结果@ahmadbajwa
    猜你喜欢
    • 1970-01-01
    • 2023-01-17
    • 2021-02-05
    • 2023-03-28
    • 2012-02-19
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多