Given an arbitrary ViewGroup G with an arbitrary collection of child views, how can I detect when the user clicks on any of the child views? In this case, I want to draw a highlight for G.
I could add an onClick listener for each child, but I'm trying to avoid that so that the code doesn't have to be changed when the layouts change.
Alternatively, I could add onTouch handlers to G and set the highlight during ACTION_DOWN. However, this would trigger for actions that don't actually result in clicks, such as a swipe (the swipe could be handled by ViewPager, for example, and ultimately be irrelevant to G).
My layout for G has the focusable attributes:
android:focusable="true"
android:focusableInTouchMode="true"
Thanks.
Here is how I do it:
//in onTouch method of parent, I get the coordinates of click
int x = ((int) motionEvent.getX());
int y = ((int) motionEvent.getY());
//obtain the clickable arrea of the child as HitRect
Rect clickRect = new Rect();
Rect rect = new Rect();
imageView.getHitRect(rect);
//ask if the area contains the coordinates of the click
if(rect.contains(x, y)){
//do some work like if onClickListener on the child was called.
return false; //you clicked here, don't need to handle other Childs
}
//ask for other childs like before...
Now, you can target the parent as the delegate of all clicks done inside it, even if it is done in a child.
EDIT:
To ignore other touch event that are not click, you can ask for how much user moved the finger:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_CANCEL:
if (Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
return true; // user mover finger too much, ignore touch
}
return false; // finger still there waiting for click
I give a square of 10 pixels to permit a confortable click, and if you exit it, I ignore it.
EXTRA:
Here is the complete code for click and long click with onTouchListener.
You could use the View.getChildCount() to loop through all child views and see if the touch intersects with the child view.
This involves getting x and y positions and calculating if it fits within the child view, use View.getChildAt(position) to get the reference to the child view .
So it would be something like this:
int childNr = theView.getChildCount();
for (int i = 0; i < childNr; i++){
YourView tmp = (YourView) theView.getChildAt(i);
if(tmp.intersects(x, y)){
do some work
}
}
here you would have to put your view variable instead of theView and the class name which handles the views instead of (YourView) and x, y are the coordinates of the pressed spot.
In your XML, you could add point all the children to the same onClick method. Inside that method you could draw the highlight to G and then do something (or nothing) for the individual child view.