Friday, November 18, 2011

Raw screen coordinates (rawX & rawY) to ListView item position

Recently had to deal with this problem, which actually turned out pretty trivial to solve (thanks to riotopsys from stackoverflow.com).

Situation as an example: you have some sort of drag&drop functionality and you want to be able to drag some view onto an item in the ListView. My solution was to implement drag&drop through WindowsManager Layout, and position the view I'm dragging using rawX, rawY coordinates. But how do I check what element is below (if I'm hovering above a ListView)?

Here the solution:

// Since ListView is vertical, I only use Y coordinate
public final int getItemPositionFromRawYCoordinates(final int rawY) {
  // Ho many items are currently displayed on the screen
  final int total = listView.getLastVisiblePosition() - getFirstVisiblePosition();
  // We will keep item coordinates here while iterating
  final int[] coords = new int[2];
  for (int i=0; i<total; i++) {
     // Since ListView recycles rows, the amount of children != amount of items in the list. There will as many children as visible items currently on the screen. That's why we counted total
    final View child = listView.getChildAt(i);
     // Get current child position on screen (these are global coordinates)
    child.getLocationOnScreen(coords);
    // We need just the top coordinate
    final int top = coords[1];
     // And bottom
    final int bottom = top + child.getHeight();
     // If our touch Y coordinate is in between, that means we are currently pointing on that child;
    if ((rawY >= top) && (rawY <= bottom)) {
      return getFirstVisiblePosition()+i;
    }
  }
  return -1;
}


That way you get either -1 if no items are currently below your pointer (which is should be weird), or actual item position :)

1 comment: