Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle touch event for items inside Recyclerview - android

i'm building a simple recyclerview with custom layout (Text view and switch) and a custom adapter.

My problem is i can't handle the click event for the switch (Which make it toggle its state), i have built a touch listener for the RecyclerView and it fires every time i click on the Switch.

After a lot of trials the switch touch listener fires also, but i want to disable the event of touch for the recyclerView if the switch is clicked.

Here is my Layout code :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60.0dip"
android:layout_weight="1.0"
android:orientation="horizontal"
android:paddingLeft="16dp">

<TextView
    android:id="@+id/category_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="false"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:text="Category Name"
    android:textAppearance="?android:textAppearanceLarge" />

<android.support.v7.widget.SwitchCompat
    android:id="@+id/category_switch"
    android:layout_width="80dp"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:checked="true"
    android:clickable="true"
    android:focusable="false"
    android:focusableInTouchMode="false"
    android:paddingRight="16dp" />

</RelativeLayout>

this is my adapter code :

public CategoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View row = layoutInflater.inflate(R.layout.single_row_category, parent, false);
    CategoryViewHolder holder = new CategoryViewHolder(row);

    return holder;
}

public void onBindViewHolder(CategoryViewHolder holder, final int position) {
    AlarmCategory thisCat = categories.get(position);

    holder.catName.setText(thisCat.getCategoryName());

    holder.catStatus.setChecked(thisCat.isOn());

    holder.catStatus.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.d("fpp", view.getClass().getName() + " is clicked");
            return true;
        }
    });
}

public class CategoryViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {

    public TextView catName;
    public SwitchCompat catStatus;

    public CategoryViewHolder(View itemView) {
        super(itemView);
        itemView.setOnCreateContextMenuListener(this);

        catName = (TextView) itemView.findViewById(R.id.category_name);
        catStatus = (SwitchCompat) itemView.findViewById(R.id.category_switch);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
        menu.add(0, 1001, 0, "Edit");//groupId, itemId, order, title
        menu.add(0, 1002, 1, "Delete");
    }
}

And here's my recyclerView touch handler :

class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

    private GestureDetector gestureDetector;
    private ClickListener clickListener;

    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));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
        if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
            clickListener.onClick(child, rv.getChildPosition(child));

            Log.d("fpp", child.getClass().getName() + " is clicked");

            return false;
        }

        return false;
    }

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

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

and in the onCreate Method i call it through :

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, new ClickListener() {
        @Override
        public void onClick(View view, int position) {
            Intent i = new Intent(CategoriesList.this, AlarmList.class);
            i.putExtra("catID", categories.get(position).getCategoryID());
            startActivity(i);
        }

        @Override
        public void onLongClick(View view, int position) {
            catPos = position;
        }
    }));

Any help please, I already tried a lot of solutions but nothing worked for sorry.

Thanks in advance.

like image 456
Fareed Avatar asked Jul 05 '15 00:07

Fareed


People also ask

How do I get touch event on android?

Try code below to detect touch events. mView. setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { //show dialog here return false; } }); To show dialog use Activity method showDialog(int).

Which method you should override to control your touch action in Android?

Android supports multiple pointers, e.g. fingers which are interacting with the screen. The base class for touch support is the MotionEvent class which is passed to Views via the onTouchEvent() method. you override the onTouchEvent() method.

Which method you should override to control your touch action?

To make sure that each view correctly receives the touch events intended for it, override the onInterceptTouchEvent() method.

How are Android touch events delivered?

The touch event is passed in as a MotionEvent , which contains the x,y coordinates, time, type of event, and other information. The touch event is sent to the Window's superDispatchTouchEvent() . Window is an abstract class. The actual implementation is PhoneWindow .


2 Answers

One way is to update your holder to handle any view clicks internally, e.g.

public class CategoryViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener, CompoundButton.OnSetCheckedListener {
    public CategoryViewHolder(View itemView) {
        super(itemView);
        itemView.setOnCreateContextMenuListener(this);
        itemView.setOnClickListener(this);

        catName = (TextView) itemView.findViewById(R.id.category_name);
        catStatus = (SwitchCompat) itemView.findViewById(R.id.category_switch);
        catStatus.setOnCheckChangedListener(this);
    }

    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // deal with catStatus change
    }

    public void onClick(View view) {
        // deal with itemView click
    }
}
like image 165
Dimitar Genov Avatar answered Oct 22 '22 20:10

Dimitar Genov


  1. Create class RecyclerTouchListener

    public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
    private GestureDetector gestureDetector;
    private ClickListener clickListener;
    
    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));
                }
            }
        });
    }
    
    @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 interface ClickListener {
        void onClick(View view, int position);
    
        void onLongClick(View view, int position);
      }
    }
    
  2. Use this Listener in Activity

    recyclerview.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerview, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, int position) {
    
               // Write your code here
    
            }
    
            @Override
            public void onLongClick(View view, int position) {
    
            }
        }));
    
like image 36
rhaldar Avatar answered Oct 22 '22 22:10

rhaldar