I have a problem with my Android app that requires touch tracking events (tracking when/where finger goes down, move, up, etc). I have to use event.getX()
and event.getY()
functions to get the current touch's coordinates.
So from what I've learned in the past few months:
MotionEvent.ACTION_DOWN
tracks the first touch downMotionEvent.ACTION_POINTER_DOWN
tracks subsequent touches downMotionEvent.ACTION_UP
tracks the last touch upMotionEvent.ACTION_POINTER_UP
tracks touch that goes upMotionEvent.ACTION_MOVE
tracks any touch movementIn my app, I'm encountering a significant problem when my first touch goes up. Lets say I have five fingers touching my device (lets call these Touch 0, 1, 2, 3, 4). Now, when I lift up Touch 0, MotionEvent.ACTION_POINTER_UP
is the action I get. Totally understandable; I get this. However, now these two things will happen:
IllegalArgumentException
telling me the pointerIndex is out of range event.getX()
and event.getY()
will give me a different finger information)I'm kind of at my wit's end on how to properly track this information. Any clues on how to properly track the information or offset the touch pointers?
I provided the general layout of what my code is but I feel like I'm not doing anything out of the ordinary (and I'm sure it is close to the example code on the Android examples?):
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getActionMasked();
int ptr_idx = event.getPointerId(event.getActionIndex());
try {
switch (action) {
case MotionEvent.ACTION_MOVE:
handleActionPointerMove(event);
break;
// Order of touch downs doesn't matter to us
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
handleActionPointerDown(event, ptr_idx);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
handleActionPointerUp(event, ptr_idx);
break;
}
}
catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
return true;
}
}
public void handleActionPointerMove(MotionEvent event) {
for (int i = 0; i < event.getPointerCount(); i++) {
handleInformation(event.getX(i), event.getY(i));
}
}
public void handleActionPointerDown(MotionEvent event, int ptr_idx) {
handleInformation(event.getX(ptr_idx), event.getY(ptr_idx));
}
public void handleActionPointerUp(MotionEvent event, int ptr_idx) {
handleInformation(event.getX(ptr_idx), event.getY(ptr_idx));
}
public void handleInformation(int x, int y) {
// Figures out what x+y means to us (are we in a certain box within the app? outside in clear zones? etc
}
Well after thinking about it for a night I've gotten it to work doing this before calling MotionEvent.getX()
and MotionEvent.getY()
:
public int getAdjustment(int ptr_idx) {
int adjust = 0;
for (int i = 0; i < event.getPointerCount(); i++) {
// Get Actual Pointer Index of touch
int adjustedPointerIndex = event.getPointerId(i);
// If we've found the current touch's pointer index AND
// the pointer index doesn't equal the sequential event's
// pointers
if ((adjustPointerIndex == ptr_idx) && (i != adjustPointerIndex)) {
adjust = (adjustPointerIndex - i);
break;
}
}
return adjust;
}
// Example Function using getAdjustment(int ptr_idx)
public void handleActionPointerUp(MotionEvent event, int ptr_idx) {
int adjustment = ptr_idx - getAdjustment(ptr_idx);
handleInformation(event.getX(adjustment), event.getY(adjustment));
}
Explanation of the for loop statement:
Basically, lets say we have 4 touches (Touch 0, 1, 2, 3). Now we have lifted up Touch 0 and now we have Touch 1, 2, 3. Android will see these touches as 0, 1, 2 and the actual pointer indices as 1, 2, 3. To get the correct adjustment, I iterate through the MotionEvent
's pointers (this is 0, 1, 2 right now in the for loop).
Now, if for some reason Touch 0 or any touch in between is taken out, we must adjust the pointer index as getX()
and getY()
doesn't understand the touch's actual pointer index. It only takes in indices 0, 1, 2 even though we have pointer indices 1, 2, 3. Thus, if we've reached the correct current touch pointer index BUT the MotionEvent
's touch index does not equal correct touch pointer index, we adjust it by doing adjust = adjustPointerIndex-i
.
After doing that, just subtract it from the current ptr_idx
we're analyzing and we get a value that getX()
and getY()
can understand without IllegalArgumentException
for a pointerIndex out of range.
Will explain more thoroughly if that doesn't make sense and if someone has a way more elegant solution please let me know because I'm sure this is not a great way to handle this. I'd rather mark someone else's answer as the approved answer.