5

In my application I have a Touchlistener for my ListView. With the TouchListener I'm able to get the X and Y coordinates from the touch event. Now I want to get the clicked item from the ListView. How can I get the position of the click item in the listView only with an onTouchListener? I do not want to use a onItemClickedListener.

Cilenco
  • 6,951
  • 17
  • 72
  • 152

4 Answers4

21
switch (motionEvent.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
                if (mPaused) {
                    return false;
                }

                // TODO: ensure this is a finger, and set a flag

                // Find the child view that was touched (perform a hit test)
                Rect rect = new Rect();
                int childCount = mListView.getChildCount();
                int[] listViewCoords = new int[2];
                mListView.getLocationOnScreen(listViewCoords);
                int x = (int) motionEvent.getRawX() - listViewCoords[0];
                int y = (int) motionEvent.getRawY() - listViewCoords[1];
                View child;
                for (int i = 0; i < childCount; i++) {
                    child = mListView.getChildAt(i);
                    child.getHitRect(rect);
                    if (rect.contains(x, y)) {
                        mDownView = child; // This is your down view
                        break;
                    }
                }

                if (mDownView != null) {
                    mDownX = motionEvent.getRawX();
                    mDownPosition = mListView.getPositionForView(mDownView);

                    mVelocityTracker = VelocityTracker.obtain();
                    mVelocityTracker.addMovement(motionEvent);
                }
                view.onTouchEvent(motionEvent);
                return true;
            }

i am get it from SwipeListView Jake Wharton

Ozik Abdullaev
  • 1,026
  • 1
  • 9
  • 26
  • 5
    That works really good but if I scroll down in the ListView I get the wrong view. How can I implement logic to get the real item even if I scroll down in the ListView? – Cilenco Jun 30 '13 at 18:35
  • Thanks for the solution, it works quite well in my custom listview – user2138983 Jul 12 '13 at 10:14
  • Am testing this with a custom view, and it's brilliant! – JWL Jul 25 '13 at 18:52
  • @Cilenco: here the `listView.getChildAt(...)` does not care about scroll. It only return views from the list which are actually visible at screen. If you want to get the "Item" you need to ask the adapter and use getFirstVisiblePosition like this: `mListView.getAdapter().getItem(i + mListView.getFirstVisiblePosition());` – François BOURLIEUX Jul 27 '15 at 15:00
4

the best way it to use this methods pointToPosition(int x, int y) and pointToRowId(int x, int y)

ant
  • 397
  • 1
  • 5
  • 19
2

If it is not mandatory that you use a TouchListener, I'd highly recommend using an OnItemClickListener. It will simplify your life greatly.

Other than that, you'll have to get the current offset and scroll position of the ListView, the height of each row and then do some math to determine whether the point (x,y) lies in the polygon of each row. Since the rows are rectangles that math isn't too difficult, but using OnItemClickListener would be much, much easier.

Additionally, if you do need to use TouchListener, you could also use OnItemClickListener to set a value on your Adapter class (or somewhere else) indicating the most recent item clicked. Then, in your TouchListener you could check that value and use that to correlate the (x,y) coordinate and ListView item. This, of course, depends on the OnItemClickListener being run first. If the inverse is true, you could make it work but instead store the touch position in using the TouchListener and then correlate it in the OnItemClickListener.

J David Smith
  • 4,780
  • 1
  • 19
  • 24
1

You class can implement both View.OnTouchListener, AdapterView.OnItemClickListener

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    if(motionEvent.getAction() == MotionEvent.ACTION_UP){
        Log.d(TAG, "ontouch: UP");

     **// Here you can figure if it was simple item click event.
        // We return false only when user touched once on the view. 
        // this will be handled by onItemClick listener.**

        if(lastAction == -1){
            lastAction = MotionEvent.ACTION_UP;
            view.clearFocus();
            return true;
        }
        return false;
    }
    else if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
        Log.d(TAG, "ontouch: DOWN");
        return false;
    }
    else {
        // This is all action events. 
        lastAction = -1;
        return true;
    }
}



@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
     // We come here after onTouch event figured out that its a simple touch event and needs to be handled here.
    }
Vikas
  • 4,263
  • 1
  • 34
  • 39