0

I want to build a RecyclerView with a few columns within each row that should be clickable to different events. Unfortunately, I haven't been able to determine which onclick is being clicked within the row, as they all call the same method. What's the best way to handle this? Should I declare multiple views within the row and assign an onclick to each View?

Here is my recyclerview.xml file:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:text="Description"
            android:id="@+id/description_textview"
            android:layout_width="180dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:paddingLeft="4dp"
            />

        <TextView
            android:text="99"
            android:id="@+id/qty_textview"
            android:layout_width="60dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:layout_toRightOf="@id/description_textview"
            android:gravity="center"
            />

        <TextView
            android:text="N"
            android:id="@+id/accept_textview"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:layout_toRightOf="@id/qty_textview"
            android:gravity="center"
            />

    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorBackgroundGray"
        android:layout_below="@id/layout"
        style="?android:listSeparatorTextViewStyle"
        />

</RelativeLayout>

Here is my recyclerview holder code (normal recyclerview). I want to replace the onLongClick event with a different column:

private class RecyclerHolder2 extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
    private TextView descriptionTextView;
    private TextView qtyTextView;
    private TextView acceptTextView;
    private VerificationModel verificationModel;

    public RecyclerHolder2(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);
        itemView.setOnLongClickListener(this);
        descriptionTextView = (TextView) itemView.findViewById(R.id.description_textview);
        qtyTextView = (TextView) itemView.findViewById(R.id.qty_textview);
        acceptTextView = (TextView) itemView.findViewById(R.id.accept_textview);
    }

    public void bindRecyclerData(VerificationModel newItem) {
        verificationModel = newItem;
        descriptionTextView.setText(verificationModel.getDescription());
        qtyTextView.setText(verificationModel.getQty());
        acceptTextView.setText(verificationModel.getAccept());
    }

    @Override
    public void onClick(View v) {
        boolean accepted = true;
        for (int i = 0; i < mVerifys.size(); i++) {
            if (mVerifys.get(i).equals(verificationModel)) {
                if (mVerifys.get(i).getAccept().equals("N")) {
                    mVerifys.get(i).setAccept("Y");
                    mVerifys.get(i).setSelected(true);
                    Timber.d(verificationModel.getDescription() + " was accepted");
                } else {
                    mVerifys.get(i).setAccept("N");
                    mVerifys.get(i).setSelected(false);
                    Timber.d(verificationModel.getDescription() + " was unaccepted");
                }
            }
            if (mVerifys.get(i).getAccept().equals("N")) {
                accepted = false;
            }
        }
        mRecyclerAdapter2.notifyDataSetChanged();
        if (accepted) {
            mAcceptedButton.setEnabled(true);
        }

    }

    @Override
    public boolean onLongClick (View v) {
        Timber.d(verificationModel.getDescription() + " will be adjusted");
        Intent intent = new Intent(VerificationDetailActivity.this, InvoiceAuthorizationActivity.class);
        startActivity(intent);
        return true;
    }
}
Jay
  • 614
  • 5
  • 22
  • I think this is a good way to solve your issue: https://stackoverflow.com/questions/36369913/how-to-implement-multi-select-in-recyclerview – Sajad Bin Nazir Aug 14 '17 at 19:40

4 Answers4

2

Right now, you're setting your listeners like this:

    itemView.setOnClickListener(this);
    itemView.setOnLongClickListener(this);

There are two different ways you can achieve what you're looking for.

The first is to use the same View.OnClickListener for each view, and then change what you do based on the clicked view's ID.

public RecyclerHolder2(View itemView) {
    super(itemView);
    ...
    descriptionTextView.setOnClickListener(this);
    descriptionTextView.setOnLongClickListener(this);
    qtyTextView.setOnClickListener(this);
    qtyTextView.setOnLongClickListener(this);
    acceptTextView.setOnClickListener(this);
    acceptTextView.setOnLongClickListener(this);
    ...
}

@Override
public void onClick(View v) {
    if (v.getId() == R.id.description_textview) {
        ...
    }
    else if (...) {
        ...
    }
}

The second (and the one I recommend) is to use a different View.OnClickListener() for each view. This will cause you to write a little more code, but makes it more obvious that different clicks do different things. (And if you're using RetroLambda you can wind up omitting most of the boilerplate).

private View.OnClickListener descriptionListener = new View.OnClickListener() {

    @Override
    public void onClick(View view) {
        ...
    }
};

private View.OnClickListener quantityListener = new View.OnClickListener() {

    @Override
    public void onClick(View view) {
        ...
    }
};

public RecyclerHolder2(View itemView) {
    super(itemView);
    ...
    descriptionTextView.setOnClickListener(descriptionListener);
    qtyTextView.setOnClickListener(quantityListener);
    ...
}
Ben P.
  • 52,661
  • 6
  • 95
  • 123
0

You can call getAdapterPosition() from your ViewHolder, which returns the position of the item in the RecyclerView. And using that position you can find which row has been clicked.

The position that is being returned is the position based on the total items in the RecyclerView and not just the items that are visible on the screen.

Bob
  • 13,447
  • 7
  • 35
  • 45
  • Sorry, maybe my question wasn't clear. I already have an event that responds to which row is clicked. I want to respond to which COLUMN has been clicked. – Jay Aug 14 '17 at 19:44
  • Instead of setting the `clickListener` to the `itemView`, you should set it to individual `view` (or column). – Bob Aug 14 '17 at 19:49
0

You sould listen at your wanted TextView. Using itemView.setOnClickListener(this); you listen to entire item of adapter. You should use acceptTextView.setOnClickListener(this); because you want to listen to specific view and in onClick() method check for clicked item.

switch(view.getId()) {
   case R.id.accept_textview:
       // do what you want when click accept textview
   break;
}
Cătălin Florescu
  • 5,012
  • 1
  • 25
  • 36
0

The most clean way to handle click events is to use Butterknife library and have a separate method for all clicks. It removes so much boilerplate code and really easy to work with. See how to use Butterknife here - http://jakewharton.github.io/butterknife/

Another way is to provide different onClick methods for each TextView. Like this

android:onClick="textButton1Clicked"

Another approach is to get the ID of the TextViews in the onclick and see which on the user clicked

 if (view.getID() == R.id.textView1) {

} else (view.getID() == R.id.textView2) {

} else (view.getID() == R.id.textView3) {

}

You can also use a switch statement for better maintainability.

Ankit Sharma
  • 663
  • 1
  • 5
  • 17