I have a ViewPager inside every row of a ListView. It works fine, it changes the views inside it when the user use the swipe gesture, but it prevents the ListView's onItemClick method to be called. I know that the ViewPager is the culprit because when I hide it, the onItemClick is called, so this is what I am trying:
I have created a ViewGroup to be the row (RowView). This ViewGroup has onInterceptTouchEvent
overriden to avoid the ViewPager to handle further touch events when I detect a click. But the onItemClick callback is still not being called. And the list selector doesn't show either on click. I want this two features to work.
This is how the onInterceptTouchEvent from RowView looks like:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int actionMasked = ev.getActionMasked();
switch(actionMasked) {
case MotionEvent.ACTION_DOWN:
Log.d("RowView", "OnInterceptTouchEvent - Down");
tapDetector.onTouchEvent(ev);
return false;
case MotionEvent.ACTION_CANCEL:
Log.d("RowView", "OnInterceptTouchEvent - Cancel");
tapDetector.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
if(tapDetector.onTouchEvent(ev)) {
Log.d("RowView", "OnInterceptTouchEvent - UP!");
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
Any suggestions to solve this?
EDIT: Not working example about how the onItemClick in MainActivity is not called when the ViewPager is active (Lollipop list selector doesn't appear either)
MainActivity
ListView listView = (ListView) findViewById(R.id.main_list);
listView.setAdapter(new MainListAdapter(this, 30));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, "onItemClick: " + position);
}
});
List item XML:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:descendantFocusability="blocksDescendants"
>
<TextView
android:id="@+id/row_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
/>
<android.support.v4.view.ViewPager
android:id="@+id/row_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
/>
</RelativeLayout>
List adapter:
public class MainListAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private int count;
public MainListAdapter(Context context, int count) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.count = count;
}
@Override
public int getCount() {
return count;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null) {
holder = new ViewHolder();
convertView = createRow(parent, holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(Integer.toString(position));
int randomPages = (int) (new Random().nextDouble()*5+2);
holder.viewPager.setAdapter(new NumAdapter(context, randomPages));
return convertView;
}
private View createRow(ViewGroup parent, ViewHolder holder) {
View view = inflater.inflate(R.layout.row_main_listview, parent, false);
holder.textView = (TextView) view.findViewById(R.id.row_num);
holder.viewPager = (ViewPager) view.findViewById(R.id.row_viewpager);
view.setTag(holder);
return view;
}
private static class ViewHolder {
public TextView textView;
public ViewPager viewPager;
}
}
ViewPager's Adapter:
public class NumAdapter extends PagerAdapter {
private LayoutInflater inflater;
private int count;
public NumAdapter(Context context, int count) {
this.inflater = LayoutInflater.from(context);
this.count = count;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView textView = (TextView) inflater.inflate(R.layout.page_viewpager, container, false);
textView.setText("Page " + position);
container.addView(textView);
return textView;
}
@Override
public int getCount() {
return count;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
}
I think this should do the trick.
I hope this will help you.
I think better override listview onintercepter than viewgroup.
TouchEvent Flow simply :
Acitivity touch event - > viewgroup.dispatchtouchevent -> viewgroup.intercepter..-> view.dispatchtouch... -> .....
in this case list.dispatch call. toss event to
ViewPager.dispatch
. but beforeViewPager.dispatchtouchevent
, callListView.intercepterTouchEvent
.if
dispatchTouchEvent
returnfalse
call parentView
'sTouchEvent
but returntrue
call flow descent.if
intercepterTouchEvent
returntrue
don't calling childdispatchTouchEvent
but returnfalse
calling childdispatchTouchEvent
. solistview.intercepterTouchEvent
returntrue
, calling onItemClick
.so if
listView.intercepterTouchEvent
returntrue
, not swipedviewPager
items.you can know user's action swipe or click 2 way.
TouchEvent
andguesturedetector
..in listview's
IntercepterTouchEvent(Event ev);
you can swipe speed about 100 or move amount 100 pixel. if not perform click event.
i hope this text can help you......
and add edit some code blow.
You need to do one of the following:
Set a
setOnClickListener
on theViewpager
's child or findI hope this may help you.
I would suggest to set
OnClickListener
on eachViewPager
instance itself and avoid usage ofonItemClickListener
of the ListView. You can then completely removeonInterceptTouchEvent()
too. That would be the simplest and stable solution. Less code - less bugs ;)The idea is to do the click listener on the view pager and not the listView
When adding the viewPager in the getView method, set its tag to be the position of the row
Then add the click listener to the viewPager (also in getView)
The problem is with the list adapters viewholder. I had a similar issue when i was trying to implement same feature (viewpager inside a listview row). I resolved it by doing this---- Set the onclicklistener on viewholder object instead of setting on listview directly. To do this you have to implement onitemclicklistener on your adapter class.