开发者

Trouble with detecting gestures over ListView

I have an Activity that contains a ViewFlipper. The ViewFlipper includes 2 layouts, both of which are essentially just ListViews.

So the idea here is that I have two lists and to navigate from one to the other I would use a horizontal swipe.

I have that working. However, what ever list item your finger is on when the swipe begins executing, that item will also be long-clicked.

Here is the relevant code I have:

public class MyActivity extends Activity implements OnItemClickListener, OnClickListener {

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

    private GestureDetector mGestureDetector;
    View.OnTouchListener mGestureListener;

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    if (mCurrentScreen != SCREEN_SECONDLIST) {
                        mCurrentScreen = SCREEN_SECONDLIST;
                        mFlipper.setInAnimation(inFromRightAnimation());
                        mFlipper.setOutAnimation(outToLeftAnimation());
                        mFlipper.showNext();
                        updateNavigationBar();
                    }
                }
                else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    if (mCurrentScreen != SCREEN_FIRSTLIST) {
                        mCurrentScreen = SCREEN_FIRSTLIST;
                        mFlipper.setInAnimation(inFromLeftAnimation());
                        mFlipper.setOutAnimation(outToRightAnimation());
                        mFlipper.showPrevious();
                        updateNavigationBar();
                    }
                }
            } catch (Exception e) {
                // nothing
            }
            return true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event))
            return true;
        else
            return false;
    }





    ViewFlipper mFlipper;

    private int mCurrentScreen = SCREEN_FIRSTLIST;

    private ListView mList1;
    private ListView mList2;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.layout_flipper);

        mFlipper = (ViewFlipper) findViewById(R.id.flipper);

        mGestureDetector = new GestureDetector(new MyGestureDetector());
        mGestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (mGestureDetector.onTouchEvent(event)) {
                    return true;
                }
                return false;
            }
        };

        // set up List1 screen

        mList1List = (ListView)findViewById(R.id.list1);
        mList1List.setOnItemClickListener(this);
        mList1List.setOnTouchListener(mGestureListener);

        // set up List2 screen
        mList2List = (ListView)findViewById(R.id.list2);
        mList2List.setOnItemClickListener(this);
        mList2List.setOnTouchListener(mGestureListener);

    }

    …
}
开发者_JS百科

If I change the "return true;" statement from the GestureDetector to "return false;", I do not get long-clicks. Unfortunately, I get regular clicks.

Does anyone know how I can get around this?


Just to throw in a completely different answer with a completely different approach...

I've made a custom view called SwipeView, it's open source etc etc blah blah blah. It should let you do what you want to do as simply as going:

mSwipeView.addChild(myList1);
mSwipeView.addChild(myList2);

You won't have to mess about with gesture detectors or anything, and the the swipe should follow your finger as you do it...

(This reads like a terrible terrible advert, please excuse me. It's been a long day ;)

Have some wonderful links:

http://jasonfry.co.uk/?id=23

http://jasonfry.co.uk/?id=24

https://jasonfry.co.uk/blog/android-swipeview-update/


Since you're using a GestureDetector, the thing to do is implement SimpleGestureDetector.onLongPress(MotionEvent e) for handling long clicks. However, you can't know the listitem that's been long-pressed from there, so you need to remember it from the normal onItemLongClick().

class MyGestureDetector extends SimpleOnGestureListener {
    ...
    @Override public void onLongPress(MotionEvent e) {
        if (longClickedItem != -1) {
           Toast.makeText(MainActivity.this, "Long click!", Toast.LENGTH_LONG).show();
        }           
    }
}

int longClickedItem = -1;

@Override
public boolean onItemLongClick(AdapterView<?> list, View view, int position, long id) {
    longClickedItem = position;
    return true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    // Reset longclick item if new touch is starting
    if (event.getAction()==MotionEvent.ACTION_DOWN) {
        longClickedItem = -1;
    }

    if (mGestureDetector.onTouchEvent(event))
        return true;
    else
        return false;
}

I have tested this and it seems to work fine.


Go you your gestureDetector and set

 mGestureDetector.setIsLongpressEnabled(false);

This will prevent long press events from being detected.


[EDIT]Scratch that, totally wrong.

I think you would have to update this part, and detect if you were scrolling left or right, and return true if you were in a swiping state. Or at least that is where i would look first.

 mGestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (mGestureDetector.onTouchEvent(event)) {
                    return true;
                }
                return false;
            }
        };

Continuing with my poor example, sorry.

Within the onTouch i believe you can test the event.getAction() and determine if a long click has occured. If it has, and your in a flinging motion, then return true as to capture the long click.

Afraid this is more of a suggestion than a definitive answer.

Also have you check the other on[methods] that you can override from the SimpleOnGestureListener. Just checked and

@Override
public void onLongPress(MotionEvent e) {
    // TODO Auto-generated method stub
    super.onLongPress(e);
}

might be something you could experiment with.


I developed a custom component derived from horizontalScrollView that does this. I have listViews as the child views and swipe without long-presses. It backed by a listAdapter, which could be anything you want (ArrayAdapter, CursorAdapter...).It loads up to three child views and then on flipping, just swaps them on either side. Most of this is kanged from ListView and needs to be refactored. Its way too long to post here directly.

http://pastie.org/1480091


Remove your getListView().setOnItemLongClickListener

Add in your class MyGestureDetector :

public void onLongPress(MotionEvent e) {
    final int position = getListView().pointToPosition((int) e.getX(),
            (int) e.getY());
    // what you want do
    super.onLongPress(e);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜