How to get clicks on RecyclerView (NOT the children)

懵懂的女人 提交于 2019-12-01 14:57:33

问题


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 a RecyclerView?

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 MotionEvents 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!