How can you detect which view you are passing over when performing a touch event?
I want to know how I can detect child views if I move a view from one ViewGroup to another ViewGroup, particularly when doing a touch event. Is there a method I can call that will let me know which views i'm "hovering" over?
What I'm doing right now is when I开发者_开发百科 detect an ACTION_MOVE event on my view i'm raising it to the top level parent so that it can move and be drawn within the entire window ( and not just inside it's original parent bounds ), then I want to move the view across to a different ViewGroup and on ACTION_UP attach the view to that ViewGroup.
Inspired by Ami's response, but discovering that MotionEvent#getX()/getY() along with View#getTop()/etc return coordinates wrt the parent View, I ended up doing the following below to operate in screen coordinates, allowing me to work across ViewGroups:
private boolean inRegion(float x, float y, View v) {
v.getLocationOnScreen(mCoordBuffer);
return mCoordBuffer[0] + v.getWidth() > x && // right edge
mCoordBuffer[1] + v.getHeight() > y && // bottom edge
mCoordBuffer[0] < x && // left edge
mCoordBuffer[1] < y; // top edge
}
whose usage inside an OnTouchListener is e.g.:
boolean inside = inRegion(event.getRawX(), event.getRawY(), targetView);
I think I found a simpler way to do this.
- Create an ArrayList of possible targets
- Call this method from your touch event, supplying your targets list and the coords
private View findView(float x, float y, ArrayList<View> targets) { final int count = targets.size(); for (int i = 0; i < count; i++) { final View target = targets.get(i); if (target.getRight() > x && target.getTop() < y && target.getBottom() > y && target.getLeft() < x) { return target; } } return null; }
I found Sebastian Roth's answer very helpful with resources, but since it wasn't really an answer to my question, I thought I'd share what I came up with.
Here is the code I use to detect views ( only views that will accept a drop that is ) given a coordinate on the screen.
private DropView findDropTarget( int x, int y, int[] dropCoordinates ){
final Rect r = mRectTemp;
final ArrayList<DropView> dropTargets = ((main) context).getBoardDropTargets();
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
final DropView target = dropTargets.get(i);
target.getHitRect(r);
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
if (r.contains(x, y)) {
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
return target;
}
}
}
Ok, first off mRectTemp is just an allocated Rectangle so you don't have to keep creating new ones ( I.E. final Rect r = new Rect() )
The next line dropTargets is a list of views that will accept a drop in my app. Next I loop through each view.
I then use getHitRect(r) to return the screen coordiantes of the view.
I then offset the coordiantes to account for the notification bar or any other view that could displace the coordiantes.
finally I see if x and y are inside the coordinates of the given rectangle r ( x and y are the event.rawX() and event.rawY() ).
It actually turned out to be simpler then expected and works very well.
Read this:
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent)
I had implemented a Drag and Drop using that method.
I also highly recommend a read of the HomeScreen sourcecode, which contains this thing (kind of):
https://android.googlesource.com/platform/packages/apps/Launcher2
精彩评论