Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
292 views
in Technique[技术] by (71.8m points)

android - SwipeListener on ListView and ClickListener on ListView's items

This is my old question. However this time I have provided my code as well.

I have a ListView with different types of rows. The row may contain text, image, video or something else. If I click on ImageView (inside the row) I will go to another activity to show the image in full screen, If I click on Video (inside the row) I will go to another activity to play he video.

I have implemented right to left swipe listener on my ListView. If I start the ListView swipe from an empty space in ListView, the swipe works (first and second row in below image). However if I start the ListView swipe from the ListView row's item, then the swipe doesn't work (third and fourth row in below image). If I remove the click events from ImageView and Video then the swipe works even if I start the swipe from the ListView row's item i.e. in this case the swipe works on whole ListView, no matter on which row I do the swipe.

enter image description here

How can I get rid on this problem? I think this can be achieved if I disable all the click events on the all the items inside ListView. How can do so? Is there any other way?

I want both swipe on ListView and click on ListView's item.

SwipeDetector.java - For detecting swipes on the ListView

public class SwipeDetector implements View.OnTouchListener {

private SwipeListener swipeListener;
private ListView mListView;
private int hundred;
private boolean motionInterceptDisallowed = false;

public static enum Action {
    LR, // Left to right
    RL, // Right to left
    TB, // Top to bottom
    BT, // Bottom to top
    None // Action not found
}

private static final int HORIZONTAL_MIN_DISTANCE = 30; // The minimum
// distance for
// horizontal swipe
private static final int VERTICAL_MIN_DISTANCE = 80; // The minimum distance
// for vertical
// swipe
private float downX, downY, upX, upY; // Coordinates
private Action mSwipeDetected = Action.None; // Last action

public SwipeDetector(Context context, ListView listView) {
    hundred = (int) context.getResources().getDimension(R.dimen.hundred);
    mListView = listView;
}

public boolean swipeDetected() {
    return mSwipeDetected != Action.None;
}

public Action getAction() {
    return mSwipeDetected;
}

/**
 * Swipe detection
 */@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        {
            downX = event.getX();
            downY = event.getY();
            mSwipeDetected = Action.None;
            return false; // allow other events like Click to be processed
        }
        case MotionEvent.ACTION_MOVE:
        {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

            float absX = Math.abs(deltaX);
            float absY = Math.abs(deltaY);

            if((absX >= (3 * absY)) && absX > HORIZONTAL_MIN_DISTANCE && mListView != null && !motionInterceptDisallowed) {
                mListView.requestDisallowInterceptTouchEvent(true);
                motionInterceptDisallowed = true;
            }

            if((absX >= (3 * absY)) && absX <= hundred) {
                if (deltaX > 0) {
                    mSwipeDetected = Action.RL;
                    swipeListener.onSwipe(MotionEvent.ACTION_MOVE, Action.RL, absX);
                }
            }


            return false;
        }
        case MotionEvent.ACTION_UP:
            swipeListener.onSwipe(MotionEvent.ACTION_UP, Action.BT, 0);
            if (mListView != null) {
                mListView.requestDisallowInterceptTouchEvent(false);
                motionInterceptDisallowed = false;
            }
            return false;
        case MotionEvent.ACTION_CANCEL:
            return true;
    }
    return false;
}

/**
 * Set chat send listener
 * @param listener
 */
public void setSwipeListener(SwipeListener listener) {
    swipeListener = listener;
}

public interface SwipeListener {
    void onSwipe(int event, Action action, float x);
}

}

This is how I am setting SwipeDetector on my ListView

final SwipeDetector swipeDetector = new SwipeDetector(SwipeActivity.this, mListView);
    swipeDetector.setSwipeListener(mSwipeListener);
    mListView.setOnTouchListener(swipeDetector);

My Activity implements SwipeDetector.SwipeListener

Below is overridden onSwipe() method

@Override
public void onSwipe(int event, SwipeDetector.Action action, float x) {
    switch (event) {
            case MotionEvent.ACTION_MOVE:
                System.out.println("list move");
                break;
            case MotionEvent.ACTION_UP:
                System.out.println("list up");
                break;
        }
}

In my adapter I am setting onClickListener() on my TextView, ImageView and VideoView

holder.mTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            System.out.println("item textview click");
        }
    });

holder.mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            System.out.println("item imageview click");
        }
    });

holder.mVideoView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            System.out.println("item videoview click");
        }
    });

When I start the swipe from the empty area of ListView, the ListView's swipe listener captures it. However, when I start the swipe from the TextView/ImageView/VideoView then that View's onClickListener is fired instead of parent's (ListView's) onTouchListener().

How can I implement the same? I want that when I click on ListView's item then that item's onClick should get fired and when I swipe on the ListView's item then ListView's onSwipe should get fired.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Thats Not Possible with both onClickListener for listitem and SwipeListener for List,because it gets Ambiguity between which View to Consider on touch

You Use OnSwipeTouchListener which implements onTouchListener

OnSwipeTouchListener.java

import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener (Context ctx){
        gestureDetector = new GestureDetector(ctx, new GestureListener());
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            onSwipeRight();
                        } else {
                            onSwipeLeft();
                        }
                    }
                    result = true;
                } 
                else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            onSwipeBottom();
                        } else {
                            onSwipeTop();
                        }
                    }
                    result = true;

            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public void onSwipeRight() {
    }

    public void onSwipeLeft() {
    }

    public void onSwipeTop() {
    }

    public void onSwipeBottom() {
    }
}

And use OnSwipeTouchListener on listitem

  listitem.setOnTouchListener(new OnSwipeTouchListener() {

        public void onSwipeLeft() {
            //stuff to do list view left swipe 
            Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
        }


        public boolean onTouch(View v, MotionEvent event) {
            //stuff to do on list item click
            return gestureDetector.onTouchEvent(event);
        }
    });

}); //to get click events 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...