Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting OnClickListener on RecyclerView itself not on item

I want to set an OnClickListener on a RecyclerView, not on its items so that it triggers a click event when the user clicks on the RecyclerView (even if it is empty or full of items).

  • I'm using MVVM
  • I tried mRecyclerView.setClickable(true), not working

What I want

mRecyclerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // do something
    }
});

My Adapter Class

public class TaskItemAdapter extends RecyclerView.Adapter<TaskItemAdapter.BaseItemAdapterViewHolder> {
    private static final String TAG = TaskItemAdapter.class.getSimpleName();
    private List<Task> mTaskList;
    private View.OnLongClickListener mOnLongClickListener;

    public TaskItemAdapter(List<Task> taskList, View.OnLongClickListener longClickListener) {
        mTaskList = taskList;
        mOnLongClickListener = longClickListener;
    }

    @NonNull
    @Override
    public BaseItemAdapterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (parent instanceof RecyclerView) {
            int layoutId = R.layout.item_list_main;
            View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
            view.setFocusable(true);
            return new BaseItemAdapterViewHolder(view);

        } else {
            throw new RuntimeException(TAG + "Not bound to recyclerView");
        }
    }

    @Override
    public void onBindViewHolder(@NonNull BaseItemAdapterViewHolder holder, int position) {
        Task task = mTaskList.get(position);
        holder.mItemTextView.setText("- " + task.getName());

        holder.itemView.setTag(task);
        holder.itemView.setOnLongClickListener(mOnLongClickListener);
    }

    @Override
    public int getItemCount() {
        return mTaskList.size();
    }

    public void loadItems(List<Task> taskList) {
        mTaskList = taskList;
        notifyDataSetChanged();
    }

    public class BaseItemAdapterViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.item_textView)
        TextView mItemTextView;

        public BaseItemAdapterViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}
like image 477
MohammadL Avatar asked Jun 26 '18 13:06

MohammadL


People also ask

Where do you add the android onClick attribute to make items in a RecyclerView respond to clicks?

Where do you add the android:onClick attribute to make items in a RecyclerView respond to clicks? In the layout file that displays the RecyclerView, add it to the element. Add it to the layout file for an item in the row.


3 Answers

mRecyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        return true;
    }
});

Then just handle the type of MotionEvent you want. Return true if you don't want the RecylerView doing anything else with it.

like image 181
Matt Avatar answered Oct 22 '22 18:10

Matt


From View.OnTouchListener onTouch() press and release event. it is possible to trigger the views.

like image 31
Dhanraaj Sreenagesh Avatar answered Oct 22 '22 19:10

Dhanraaj Sreenagesh


A RecyclerView does not provide OnClick callbacks by default. So you can create an OnTouchListener to consume click events.

public class RVClickHandler implements View.OnTouchListener {

    private RecyclerView mRecyclerView;
    private float mStartX;
    private float mStartY;

    public RVClickHandler(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        boolean isConsumed = false;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mStartX = event.getX();
                mStartY = event.getY();
                break;
            }
            case MotionEvent.ACTION_UP: {
                float endX = event.getX();
                float endY = event.getY();
                if(detectClick(mStartX, mStartY, endX, endY)) {
                    //Ideally it would never be called when a child View is clicked.
                    //I am not so sure about this.
                    View itemView = mRecyclerView.findChildViewUnder(endX, endY);
                    if(itemView == null) {
                        //RecyclerView clicked
                        mRecyclerView.performClick();
                        isConsumed = true;
                    }
                }
                break;
            }
        }
        return isConsumed;
    }

    private static boolean detectClick(float startX, float startY, float endX, float endY) {
        return Math.abs(startX-endX) < 3.0 && Math.abs(startY-endY) < 3.0;
    }

}

add this to your RecyclerView as follows

recyclerView.setOnTouchListener(new RVClickHandler(recyclerView));

Now you can attach a normal OnClickListener to handle clicks.

recyclerView.setOnClickListener((v) -> {
    //Called when an empty space is clicked inside RecyclerView.
});

Click events for child views can be handled inside the ViewHolder

like image 37
Sakchham Avatar answered Oct 22 '22 17:10

Sakchham