code
code

Reputation: 2163

Defining a RecyclerView's onCLickListener in an Activity

A RecyclerView is different from a ListView because it doesn't offer an onItemCLickListener class to handle click events.

This can be tackled if not a lot is happening behind the scenes when an item is clicked, by defining an onClickListener in the ViewHolder.

What if the text or whatever that has to be passed to the next Activity doesnt really exist in the views that the ViewHolder has access to, but is rather a part of the Activity which has the RecyclerView?

In that case, the onClickListener must be implemented inside the activity so that the text can be forwarded. It is possible.

  1. One way is to add an Invisible View holding that text, and then doing what has been done before; implementing onClickListener in the Adapter.

  2. Pass that text, somehow, to the Adapter.

How can "2." be implemented?

Upvotes: 18

Views: 47710

Answers (6)

Hamed Rahimi
Hamed Rahimi

Reputation: 59

I had this problem with the first good answer. Had a problem(Context Error).

I put the following code in onBindViewHolder.

In adapter :

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((YouActivityClass) v.getContext()).onClickCalled("your argument here");
            }
        });

In Activity :

    public void onClickCalled(String anyValue) {
        // Call another acitivty here and pass some arguments to it.

    }

The Whole

Upvotes: 3

pRaNaY
pRaNaY

Reputation: 25312

See the example below to create RecyclerView OnClick.

Example Code:

public class ContentAdapter extends RecyclerView.Adapter<ContentAdapter.ViewHolder> {

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

private final List<ContentItem> items;
private final OnItemClickListener listener;

public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
    this.items = items;
    this.listener = listener;
}

@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false);
    return new ViewHolder(v);
}

@Override public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(items.get(position), listener);
}

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

static class ViewHolder extends RecyclerView.ViewHolder {

    private TextView name;
    private ImageView image;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.name);
        image = (ImageView) itemView.findViewById(R.id.image);
    }

    public void bind(final ContentItem item, final OnItemClickListener listener) {
        name.setText(item.name);
        Picasso.with(itemView.getContext()).load(item.imageUrl).into(image);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                listener.onItemClick(item);
            }
        });
    }
}
}

And Use RecyclerView Adapter using below code:

recycler.setAdapter(new ContentAdapter(items, new ContentAdapter.OnItemClickListener() {
@Override public void onItemClick(ContentItem item) {
    Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
}
}));

See Set a click listener to a RecyclerView

Hope it helped you.

Upvotes: 26

chetan muliya
chetan muliya

Reputation: 81

its easy,we don't have create interfaces look at my code just put this small code and we are

@Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
      holder.img.setImageDrawable(img[position%img.length]);
        holder.bodyPartName.setText(bodyPart[position]);
        if(position==0) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Context c = v.getContext();
                    Intent intent = new Intent(c, BodyPartExcercise.class);
                    c.startActivity(intent);
                }
            });
        }
    }

Upvotes: -1

34m0
34m0

Reputation: 5955

Where ListView has an onItemClickListener, RecyclerView has addOnItemTouchListener.

You can provide the listener to the recycler view from within the activity, thus the scoping will be such that the listener should be able to reference the text.

You could use something like following implementation of the OnItemTouchListener which also works to capture left and right swipes.

public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

    private static final String TAG = "RecyclerTouchListener";

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private static final int SWIPE_MAX_OFF_PATH = 250;

    private OnTouchActionListener mOnTouchActionListener;
    private GestureDetectorCompat mGestureDetector;

    public static interface OnTouchActionListener {
        public void onLeftSwipe(View view, int position);
        public void onRightSwipe(View view, int position);
        public void onClick(View view, int position);
    }

    public RecyclerTouchListener(Context context, final RecyclerView recyclerView,
                             OnTouchActionListener onTouchActionListener){

        mOnTouchActionListener = onTouchActionListener;
        mGestureDetector = new GestureDetectorCompat(context,new GestureDetector.SimpleOnGestureListener(){

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.d(TAG, "On Single Tap Confirmed");
            // Find the item view that was swiped based on the coordinates
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            int childPosition = recyclerView.getChildPosition(child);
            mOnTouchActionListener.onClick(child, childPosition);
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2,
                               float velocityX, float velocityY) {
            Log.d(TAG, "onFling: " + e1.toString() + e2.toString());

            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
                    return false;
                }

                // Find the item view that was swiped based on the coordinates
                View child = recyclerView.findChildViewUnder(e1.getX(), e1.getY());
                int childPosition = recyclerView.getChildPosition(child);

                // right to left swipe
                if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {

                    Log.d(TAG, "Left Swipe");
                    if (mOnTouchActionListener != null && child != null) {
                        mOnTouchActionListener.onLeftSwipe(child, childPosition);
                    }

                } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Log.d(TAG, "Right Swipe");
                    if (mOnTouchActionListener != null && child != null) {
                        mOnTouchActionListener.onRightSwipe(child, childPosition);
                    }
                }
            } catch (Exception e) {
                // nothing
            }

            return false;
        }
    });
}

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        // do nothing
    }

}

Then in your activity add your listener along the lines of

 mRecyclerView.addOnItemTouchListener(
        new RecyclerTouchListener(getActivity(), mRecyclerView,
            new RecyclerTouchListener.OnTouchActionListener() {
                @Override
                public void onClick(View view, int position) {
                }
                @Override
                public void onRightSwipe(View view, int position) {
                }
                @Override
                public void onLeftSwipe(View view, int position) {
                }
            }))

Upvotes: 1

a person
a person

Reputation: 986

This can be solved by creating your own listener and passing it to the adapter.

public interface PositionClickListener
{
    void itemClicked(int position);
}

The Activity could implement this interface, or instantiate an anonymous inner class. So your adapter could look like this:

public class MyRecyclerAdapter extends RecyclerView.Adapter
{
    public final PositionClickListener listener;

    public MyRecyclerAdapter(PositionClickListener listener)
    {
         this.listener = listener;
    }

    private void createView(int position)
    {
        View v = new View();
        v.setOnClickListener(new OnClickListener(){
            listener.itemClicked(position);
        });
    }
}

Upvotes: 3

Adnan Amjad
Adnan Amjad

Reputation: 2613

Write a public function in your activity like:

public void onClickCalled(String anyValue) {
    // Call another acitivty here and pass some arguments to it.
}

Now in your adapter's onClick funciton

@Override
public void onClick(View view) {
    ((YouActivityClass) context).onClickCalled("your argument here");
}

Upvotes: 16

Related Questions