ViewPager inside ListView row prevents onItemClick to be fired

前端 未结 9 939
南旧
南旧 2020-12-30 14:56

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 onItemC

相关标签:
9条回答
  • 2020-12-30 15:21

    You need to do one of the following:

    Set a setOnClickListener on the Viewpager's child or find

    android:descendantFocusability="beforeDescendants"
    

    I hope this may help you.

    0 讨论(0)
  • 2020-12-30 15:24

    An improvement over Adrian's answer:

    public class CustomListView extends ListView {
    
        private GestureDetector gestureDetector;
    
        public CustomListView(Context context) {
            super(context);
            gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener());
        }
    
        public CustomListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener());
        }
    
        public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener());
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public CustomListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener());
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            gestureDetector.onTouchEvent(ev);
            return super.dispatchTouchEvent(ev);
        }
    
        private class CustomListViewOnGestureListener extends GestureDetector.SimpleOnGestureListener {
            @Override
            public boolean onSingleTapUp(MotionEvent ev) {
                int firstVisiblePosition = getFirstVisiblePosition();
                int itemPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
                int childIndex = itemPosition - firstVisiblePosition;
                View view = getChildAt(childIndex);
                performItemClick(view, itemPosition, getItemIdAtPosition(itemPosition));
                return true;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-30 15:25

    I would suggest to set OnClickListener on each ViewPager instance itself and avoid usage of onItemClickListener of the ListView. You can then completely remove onInterceptTouchEvent() too. That would be the simplest and stable solution. Less code - less bugs ;)

    0 讨论(0)
  • 2020-12-30 15:28

    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.

    0 讨论(0)
  • 2020-12-30 15:31

    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 before ViewPager.dispatchtouchevent, call ListView.intercepterTouchEvent.

    if dispatchTouchEvent return false call parent View's TouchEvent but return true call flow descent.

    if intercepterTouchEvent return true don't calling child dispatchTouchEvent but return false calling child dispatchTouchEvent. so listview.intercepterTouchEvent return true, calling onItemClick.

    so if listView.intercepterTouchEvent return true, not swiped viewPager items.

    you can know user's action swipe or click 2 way. TouchEvent and guesturedetector..

    in listview's IntercepterTouchEvent(Event ev);

    VelocityTracker mVelocityTracker;
    PointF mLastPoint;
    public mListView(Context context) {
        super(context);
        init();
    }
    
    public mListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
    public mListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    
    private void init(){
        mLastPoint = new PointF();
    }
    
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    
        if(mVelocityTracker == null)
            mVelocityTracker = VelocityTracker.obtain();
        mVelocityTracker.addMovement(ev);
    
        switch (ev.getAction()){
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.computeCurrentVelocity(100);
                int x = (int)Math.abs(mVelocityTracker.getXVelocity());
                int move_x = (int)Math.abs(ev.getX() - mLastPoint.x);
                Log.d("ListView","speed : " + x +" move_x : " + move_x);
                //here x is drag speed. (pixel/s)
                // change value left right both value you want speed and move amount
                if(move_x < 100 || x <100) {
                    mLastPoint.set(ev.getX(), ev.getY());
                    return true;
                }
                break;
            case MotionEvent.ACTION_DOWN:
                mLastPoint.set(ev.getX(), ev.getY());
                break;
            case MotionEvent.ACTION_UP:
    
                mVelocityTracker.recycle();mVelocityTracker = null;
    
                break;
        }
        return super.onInterceptTouchEvent(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.

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    
        if(mVelocityTracker == null)
            mVelocityTracker = VelocityTracker.obtain();
        mVelocityTracker.addMovement(ev);
    
        switch (ev.getAction()){
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.computeCurrentVelocity(10);
                int x = (int)Math.abs(mVelocityTracker.getXVelocity());
                int move_x = (int)Math.abs(ev.getX() - mLastPoint.x);
                int move_y = (int)Math.abs(ev.getY() - mLastPoint.y);
                Log.d("ListView","speed : " + x +" move_x : " + move_x + " move_y : "+ move_y);
                if(move_x < move_y || x < 10) {
                    mLastPoint.set(ev.getX(), ev.getY());
                    return true;
                }else if(move_x > move_y){
                    return false;
                }
                break;
            case MotionEvent.ACTION_DOWN:
                mLastPoint.set(ev.getX(), ev.getY());
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("ListView", "dispatch");
        switch (ev.getAction()){
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                if(mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;}
                break;
        }
        return super.dispatchTouchEvent(ev);;
    }
    
    0 讨论(0)
  • 2020-12-30 15:35

    As your viewpaper is your listview's child,its consuming the touch events. You can prevent this by making your viewpagers child unclickable,i.e.

        TextView textView =(TextView)inflater.inflate(R.layout.page_viewpager,container, false);
    
        textView.setText("Page " + position); 
    
        textView.setClickable(false);
    
    0 讨论(0)
提交回复
热议问题