Reputation: 353
I am tring to handle touch the events in the Recycler View-:
class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private ClickListener clickListener;
private GestureDetector gestureDetector;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener){
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if(child!=null && clickListener!=null)
{
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
Log.i("TAG", "Radhe handling LongPress ");
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null && clickListener!=null && gestureDetector.onTouchEvent(e));
{
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
public static interface ClickListener{
public void onClick(View view, int position);
public void onLongClick(View view, int position);
}
Also I have the following code-:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
recyclerView = (RecyclerView) layout.findViewById(R.id.drawerList);
filterAdapter = new FilterAdapter(getActivity(), getData());
recyclerView.setAdapter(filterAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
@Override
public void onClick(View view, int position) {
Log.i("TAG", "Radhe child Clicked ");
Toast.makeText(getActivity(),"CLick",Toast.LENGTH_SHORT).show();
}
@Override
public void onLongClick(View view, int position) {
Log.i("TAG", "Radhe child Long Clicked ");
Toast.makeText(getActivity(),"Long CLick",Toast.LENGTH_SHORT).show();
}
}));
return layout;
}
Now when I run it -: and
Can somebody tell why is this happening? I don't know the reason for it. Thanks in advance.
Upvotes: 3
Views: 3100
Reputation: 9655
We can make use of kotlin Extension Functions
Usage
myView.setDebounceOnClickListener {
// your code
}
Extension function
fun View.setDebounceOnClickListener(onDebounceClick: (View) -> Unit) {
val debounceClickListener = DebounceClickListener {
onDebounceClick(it)
}
setOnClickListener(debounceClickListener)
}
Util
/**
* Solves multiple click issue on view
*
* @param debounceDelayMillis delay millis which limits the rate at which a function gets invoked
* @param onDebounceCLick a lambda block which gonna run if the interval between clicks is greater than provided delay millis
*
*/
class DebounceClickListener(
private var debounceDelayMillis: Int = 1000,
private val onDebounceCLick: (View) -> Unit
) : View.OnClickListener {
private var lastTimeClicked: Long = 0L
override fun onClick(v: View) {
if (SystemClock.elapsedRealtime() - lastTimeClicked < debounceDelayMillis) {
return
}
lastTimeClicked = SystemClock.elapsedRealtime()
onDebounceCLick(v)
}
}
Upvotes: 0
Reputation: 314
My solution
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
if(e.getAction()==MotionEvent.ACTION_DOWN) return this.mGestureDetector.onTouchEvent(e);
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && this.mListener != null && this.mGestureDetector.onTouchEvent(e)) {
this.mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
return true;
}
return false;
}
Upvotes: 0
Reputation: 3149
I usually handle click events in the adapter and interact with the fragment/activity via an interface like bellow.
In your adapter's onBindViewHolder;
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClicked(holder.aValue);
}
});
whereas mListener is an interface with a
public interface IclickListener<T> {
void onItemClicked(T object);
}
Upvotes: 3
Reputation: 1556
This should fix it:
@Override
public boolean onSingleTapUp(MotionEvent e) {
if(e.getAction()==MotionEvent.ACTION_UP)
{
//do something
}
return true;
}
Upvotes: 2
Reputation: 21783
When you call onClick
from onInterceptTouchEvent
you need to return true
to show the event has been consumed and not continue to fire events for it.
Javadoc for addOnItemTouchListener
says:
Once a listener returns true from RecyclerView.OnItemTouchListener.onInterceptTouchEvent(RecyclerView, MotionEvent) its RecyclerView.OnItemTouchListener.onTouchEvent(RecyclerView, MotionEvent) method will be called for each incoming MotionEvent until the end of the gesture.
and a false from onInterceptTouchEvent
means
continue with the current behavior and continue observing future events in the gesture.
Just to clarify within your existing code (however I'm not sure what you try to achieve with gestureDetector.onTouchEvent(e) in the if statement, make sure you're not consuming the scroll events accidentally too):
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null && clickListener!=null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
return true;
}
return false;
}
Upvotes: 7