问题
Is there any way to set an onClickListener
on a RecyclerView
?
I have a RecyclerView
with some children in it, and setting an OnClickListener
on the parent RecyclerView
. However, the onClick
doesn't fire when I click on that view. See sample code below -- we want to get clicks on the parent, NOT the children. In this scenario we don't care about clicks on the items.
I have tried doing setFocusable(false)
, setClickable(false)
, and setOnClickListener(null)
on the children to no avail. In any case I don't think the children are stealing clicks from the parent, because when I click on the area where there is no children, the clicks don't register either.
package com.formagrid.hellotest;
import android.app.Activity;
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.view.ViewGroup;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
public class HelloActivity extends Activity {
private RecyclerView mRecyclerView;
private RecyclerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new RecyclerAdapter(Arrays.asList("hi", "this", "is", "some", "text"));
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("patricia", view.toString());
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.Holder> {
public class Holder extends RecyclerView.ViewHolder {
protected TextView textView;
public Holder(TextView itemView) {
super(itemView);
this.textView = itemView;
}
}
private List<String> contents;
public RecyclerAdapter(List<String> contents) {
this.contents = contents;
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new Holder(new TextView(parent.getContext()));
}
@Override
public void onBindViewHolder(Holder holder, int position) {
holder.textView.setText(contents.get(position));
}
@Override
public int getItemCount() {
return contents.size();
}
}
}
回答1:
Is there any way to set an
onClickListener
on aRecyclerView
?
No. That is, you can set an OnClickListener
, but RecyclerView
will never call it. RecyclerView
intercepts all touch events, but never calls performClick()
, which is how View
invokes its listener.
You can, however, simulate an OnClickListener
with an OnTouchListener
and a GestureDetector
. For the GestureDetector
's listener, we can use a SimpleOnGestureListener
, implementing just the onSingleTapUp()
method.
class ClickListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
Toast.makeText(HelloActivity.this, "Clicked", 0).show();
return true;
}
};
Then we just need to feed the GestureDetector
the MotionEvent
s from an OnTouchListener
, and check the return to decide whether to consume the event, so as to not interfere with scrolling, dragging, etc.
final GestureDetector detector = new GestureDetector(HelloActivity.this, new ClickListener());
mRecyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(detector.onTouchEvent(event)) {
return true;
}
return false;
}
}
);
Please note that the above solution works with pretty much only a "simple" RecyclerView
, like the one described and given in the question. If you're using more involved item handling, like drag and drop or swipe, we'll need to handle our gesture detection a little further up the touch event chain.
To do this, we can subclass RecyclerView
and perform the detection in the dispatchTouchEvent()
method. If a single tap is detected, we simply call performClick()
, which will fire the RecyclerView
's OnClickListener
.
public class ClickableRecyclerView extends RecyclerView {
private final GestureDetectorCompat detector;
public ClickableRecyclerView(Context context) {
this(context, null);
}
public ClickableRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
detector = new GestureDetectorCompat(context, new ClickListener());
}
private class ClickListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
performClick();
return true;
}
};
@Override
public boolean dispatchTouchEvent(MotionEvent e) {
detector.onTouchEvent(e);
return super.dispatchTouchEvent(e);
}
}
Just use this subclass in place of your regular RecyclerView
, and set an OnClickListener
on it as you normally would. Additional constructors may be necessary, depending on how you're instantiating this.
回答2:
Try something like wrapping up your recyclerview inside a relativelayout or linearlayout or FrameLayout and then set the click listener to the relativelayout/linearlayout/framelayout.
<RelativeLayout
android:id="@+id/myLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
Now :
RelativeLayout rl = (RelativeLayout) findViewById(R.id.myLayout);
rl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("patricia", view.toString());
}
});
回答3:
a click event on RecycleView ? try like this:
//set android:descendantFocusability="blocksDescendants" on parent layout
//then setOnClickListener
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
**android:descendantFocusability="blocksDescendants"**
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
来源:https://stackoverflow.com/questions/38256645/how-to-get-clicks-on-recyclerview-not-the-children