Android CardView with ListView inside - onTouchListener on CardView not working

I have a map view with a list inside. I will also need a click element in the list view, and I want to be able to move the entire card using the ontouchlistener. I installed onTouchListener to view the map, but it does not work.

The code:

Put this in build.gradle:

compile 'com.android.support:cardview-v7:22.0+' 

MainActivity:

 package com.XXXXXXXX.testontouch; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.CardView; import android.view.MotionEvent; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView mylistview; private CardView mycardview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mycardview = (CardView)findViewById(R.id.mycardview); mylistview = (ListView) findViewById(R.id.myListView); List<String> your_array_list = new ArrayList<String>(); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); your_array_list.add("foo"); your_array_list.add("bar"); ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>( this, android.R.layout.simple_list_item_1, your_array_list ); mylistview.setAdapter(arrayAdapter); mycardview.setCardElevation(20); mycardview.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("TOuchedddd"); return true; } }); } } 

TOuchedddd never prints. If I remove the ListView from the card, it will start working.

So somehow, listView first uses touch events instead of the parent view of the map.

XML for MainActivity:

 <?xml version="1.0" encoding="utf-8"?> <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="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.pranapps.testontouch.MainActivity"> <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/mycardview" card_view:cardUseCompatPadding="true"> <ListView android:layout_width="match_parent" android:layout_height="fill_parent" android:id="@+id/myListView" android:dividerHeight="0.2dp" android:overScrollMode="always" android:smoothScrollbar="true" android:groupIndicator="@null" ></ListView> </android.support.v7.widget.CardView> </RelativeLayout> 

I tried both true and false for android: clickable, android: focusable and android: focusableInTouchMode. bad luck.

+2
android listview ontouchlistener android-cardview
May 08 '16 at 6:05
source share
1 answer

In Android, touch events pop up from child to parent, as you would expect. However, the parent can intercept all touch events destined for one of its children and decide to veto sending this event to the child. This is exactly what you want, if I understand correctly that your touch event should be triggered no matter what happens when you touch your map view, and then you send the touch event to the list of your children, if necessary.

To capture the touch event from CardView, you must create a custom view that subclasses it and overrides the onInterceptTouchEvent method:

 package com.pranapps.testontouch; import android.content.Context; import android.util.AttributeSet; import android.support.v7.widget.CardView; import android.view.MotionEvent; import android.view.View; public class CardViewTouchThief extends CardView { public CardViewTouchThief(Context context) { super(context); } public CardViewTouchThief(Context context, AttributeSet attrs) { super(context, attrs); } public CardViewTouchThief(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { /* * This method determines whether we want to intercept the motion. * If we return true, onTouchEvent will be called. */ return true; } } 

Then you use CardViewTouchThief, where you usually use CardView in an XML layout:

 <com.pranapps.testontouch.CardViewTouchThief xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/mycardview" card_view:cardUseCompatPadding="true"> <ListView android:layout_width="match_parent" android:layout_height="fill_parent" android:id="@+id/myListView" android:dividerHeight="0.2dp" android:overScrollMode="always" android:smoothScrollbar="true" android:groupIndicator="@null"/> </com.pranapps.testontouch.CardViewTouchThief> 

And in your activity, use your own logic for processing whenever you want the touch event to be sent to the list view.

 mycardview.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("MainActivity", "TOuchedddd"); if(mylistview!=null){ //Route all touch event to listview without logic mylistview.onTouchEvent(event); } return true; } }); 

Here is the fixed source code of the project.

+6
May 12 '16 at
source share



All Articles