Michael Dadi
Michael Dadi

Reputation: 422

Changing the Visibility of Elements in a RecyclerView Row OnClick

I have the following app I'm working on, where I am trying to make it so whenever an image in the RecyclerView is clicked, its two corresponding buttons from the row xml will become visible (they are invisible by default).

Here's my code...

MainAcitivity.Java

    package com.mdadi.animals2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.util.ArrayList;

import static android.view.View.VISIBLE;


public class MainActivity extends AppCompatActivity implements MyAdapter.OnImageListener {

    private RecyclerView list; //RecyclerView instance
    private RecyclerView.Adapter mAdapter; //Adapter
    private RecyclerView.LayoutManager mLayoutManager;
    private ArrayList<ListData> data = new ArrayList<>();
    ListData lastPosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Initialize data
        data = ListData.initData();

        final EditText editText = findViewById(R.id.editTxt);

        list = findViewById(R.id.recyclerView); //Lookup RecyclerView in activity layout
        list.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        list.setLayoutManager(mLayoutManager); //Set layout manager to position items/rows

        //Attach adapter to RecyclerView to pop items
        mAdapter = new MyAdapter(data, this);
        list.setAdapter(mAdapter);


/*        findViewById(R.id.delBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String newFact = editText.getText().toString();
                mAdapter.notifyItemInserted(listData.size() - 1);
            }
        });*/
    }

    @Override
    public void onImageClick(int position) {
        int lastPos = position;
        Button delBtn = findViewById(R.id.delBtn);
        Button nextBtn = findViewById(R.id.nextBtn);

        data.remove(R.id.delBtn);
        delBtn.setVisibility(VISIBLE);
        mAdapter.notifyItemChanged(R.id.delBtn);
        nextBtn.setVisibility(VISIBLE);
        mAdapter.notifyItemChanged(R.id.nextBtn);

        Log.d("MyActivity", position + " clicked");
    }
}

MyAdapter.Java

    package com.mdadi.animals2;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    //ViewHolder defined above
    private ArrayList<ListData> data; //ArrayList member var for ListData
    private OnImageListener mOnImageListener;
    //Pass in data array for constructor
    public MyAdapter(ArrayList<ListData> data, OnImageListener onImageListener) {
        this.data = data;
        this.mOnImageListener = onImageListener;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //Inflate custom layout
        View rootView = LayoutInflater.from(parent.getContext()).inflate
                (R.layout.recycler_view_item, parent, false);
        //Return new holder instance
        return new MyViewHolder(rootView, mOnImageListener);
    }
    //Pop data into item through holder
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        //Get data model based on position
        ListData listData = data.get(position);

        //String message = data.get(position).getDesc();
        //holder.textView.setText(message);

        //Set item views based on created views and data
        holder.textView.setText(listData.getDesc());
        holder.img.setImageResource(listData.getImgURL());
    }
    //Return total item count of list
    @Override
    public int getItemCount() {
        if (data != null)
            return data.size();
        else
            return 0;
    }
    public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private TextView textView;
        private ImageView img;
        private Button next;
        private Button delete;
        OnImageListener onImageListener;

        public MyViewHolder(View v, OnImageListener onImageListener) {
            super(v);
            textView = v.findViewById(R.id.fact);
            img = v.findViewById(R.id.image);
            next = v.findViewById(R.id.nextBtn);
            delete = v.findViewById(R.id.delBtn);
            this.onImageListener = onImageListener;

            v.setOnClickListener(this);
        }
        public void onClick(View view) {
            onImageListener.onImageClick(getAdapterPosition());
        }
    }

    public interface OnImageListener {
        void onImageClick(int position);
    }
}

ListData.Java

    package com.mdadi.animals2;

import java.util.ArrayList;

public class ListData {
    private String desc;
    private int imgURL;

    public ListData(String desc, int imgURL) {
        this.desc = desc;
        this.imgURL = imgURL;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }

    public int getImgURL() {
        return imgURL;
    }
    public static ArrayList<ListData> initData() {
        ArrayList<ListData> list = new ArrayList<>();

        list.add(new ListData("bird\n",R.drawable.bird)); //1
        list.add(new ListData("cat\n",R.drawable.cat)); //2
        list.add(new ListData("dog\n",R.drawable.dog)); //3
        list.add(new ListData("fish\n",R.drawable.fish)); //4
        list.add(new ListData("kangaroo\n",R.drawable.kangaroo)); //5
        list.add(new ListData("monkey\n",R.drawable.monkey)); //6
        list.add(new ListData("turtle\n",R.drawable.turtle)); //7
        list.add(new ListData("horse\n",R.drawable.horse)); //8
        list.add(new ListData("elephant\n",R.drawable.elephant)); //9
        list.add(new ListData("turkey\n",R.drawable.turkey)); //10

        return list;
    }
}

The problem here is that while it returns the correct position of the clicked image in logd, buttons will often be displayed for the wrong row.

Upvotes: 1

Views: 1068

Answers (1)

Cheticamp
Cheticamp

Reputation: 62841

You didn't post the XML for each RecyclerView item but I assume that each row would have its own buttons, delBtn and nextBtn, and it is these that you want to set the visibility for.

The problem is how you look up these buttons. When you do the following in the click handler:

Button delBtn = findViewById(R.id.delBtn);
Button nextBtn = findViewById(R.id.nextBtn);

You are searching for those ids from the top of the view hierarchy and outside the bounds of the item that was clicked. You actually want to do the search inside the item that is clicked.

Button delBtn = itemView.findViewById(R.id.delBtn);
Button nextBtn = itemView.findViewById(R.id.nextBtn);

Here itemView is the view layout for the row which you could pass into onImageClick() from onClick(). (Actually, take a look at your ViewHolder constructor for how to do this.)

There are a couple of other things that look unusual in your code such as

mAdapter.notifyItemChanged(R.id.delBtn);

The argument should be a position in the data array.

Upvotes: 2

Related Questions