4
\$\begingroup\$

How does one go about detecting a secondary/non-primary finger moving?

There is:

ACTION_DOWN and ACTION_UP to detect a primary finger pressing the screen / leaving the screen

ACTION_POINTER_DOWN and ACTION_POINTER_UP for subsequent fingers pressing / leaving the screen

But there is no ACTION_POINTER_MOVE for monitoring and responding to subsequent fingers moving.

Also, if I log event.getActionIndex(); it always returns '0' regardless of how many fingers are touching the screen (I'm guessing because *ACTION_MOVE* is only interested in the primary finger). So how is it possible test the subsequent fingers?

Code

case MotionEvent.ACTION_MOVE:{  
         int pointerId = event.getPointerId(pointerIndex);  

        //Finger slid to left button so set sprite left  
            if (event.getY(pointerIndex)>=renderer.leftButton("top") && event.getX(pointerIndex)<=renderer.leftButton("right")){  
                renderer.setSpriteState('l', true);  
                renderer.setSpriteState('r', false);  

        }  

            //Finger slide to the right button so set sprite right  
            else      
                if (event.getY(pointerIndex)>=renderer.rightButton("top") && event.getX(pointerIndex)>renderer.rightButton("left") && event.getX(pointerIndex)<=renderer.rightButton("right")){  
                    renderer.setSpriteState('l', false);  
                    renderer.setSpriteState('r', true);  

            }  
            break;  
\$\endgroup\$

3 Answers 3

6
\$\begingroup\$

The ACTION_MOVE event provides data for multiple fingers.

You can use event.getPointerCount() to find out how many fingers are touching the screen. Then you can loop through the pointers to get data for each one.

Example:

case MotionEvent.ACTION_MOVE:
    int count = event.getPointerCount();
    for (int i = 0; i < count; i++) {
        x[i] = event.getX(i);
        y[i] = event.getY(i);
    }

This will give you the x and y values for all of the different touch events.

\$\endgroup\$
5
  • \$\begingroup\$ Hi @IanMarkowitz I've just implemented this it does work, but how can I know which is where? What I mean is this, if I have 2 fingers on the screen and I want to perform an action when finger1 moves from area a to area b (or vice-versa) but not while it's moving within area a (or area b) - how do I do this? I assume I would need to save the positions of each of the fingers that are pressed but I have no way of knowing which is where? If you see what I mean. \$\endgroup\$ Commented May 28, 2013 at 0:02
  • \$\begingroup\$ Actually, you've answered my question - so thanks! I will as a separate one for my question above :-) \$\endgroup\$ Commented May 28, 2013 at 0:05
  • \$\begingroup\$ I've asked the new question, would be grateful if you could have a look - thanks. \$\endgroup\$ Commented May 28, 2013 at 0:36
  • \$\begingroup\$ You can use event.getPointerID(i) to get an identifier for each pointer. To keep track of a finger, you can save the ID on a down action, and check any new move actions against the saved id. \$\endgroup\$ Commented May 28, 2013 at 1:12
  • \$\begingroup\$ take a look at developer.android.com/training/gestures/multi.html \$\endgroup\$ Commented May 28, 2013 at 1:13
1
\$\begingroup\$

You can get the effective pointer index of moving finger by checking which pointer changed:

private final int MAX_POINTER = 5; // 5 different touch pointers supported on most devices
private float mLastTouchPositionX[];
private float mLastTouchPositionY[];

@Override
public boolean onTouchEvent(MotionEvent aEvent)
int tActionIndex = aEvent.getActionIndex();
int tPointerCount = aEvent.getPointerCount();
    /*
     * Check which pointer changed on move
     */
    if (tMaskedAction == MotionEvent.ACTION_MOVE) {
        for (int i = 0; i < tPointerCount && i < MAX_POINTER; i++) {
            if (mLastTouchPositionX[i] != aEvent.getX(i) || mLastTouchPositionY[i] != aEvent.getY(i)) {
                mLastTouchPositionX[i] = aEvent.getX(i);
                mLastTouchPositionY[i] = aEvent.getY(i);
                // Found new action index
                tActionIndex = i;
                break;
            }
        }
    }
...
}
\$\endgroup\$
0
\$\begingroup\$

Neither of the proposed solutions are entirely correct (or at the very least, are misleading), since instead of keeping track of the actual finger/pointer id, they are only regarding that move event's index within the MotionEvent object, which may vary depending on the number of fingers on the screen.

For example: if the user presses the screen with one finger, and then a second, then that second finger's 'x' position is read by calling event.getX(1). Once the first finger is released, the second finger's position will now be read via event.getX(0), since that event object's internal position array is now only one item long. In the above solutions, this means that the position data from the second finger will start being written to a different location in the mLastTouchPositionX[] array, once the user releases the first finger.

In order to keep track of a finger throughout its lifespan, you must call event.getPointerId(i) (as mentioned by OP and in one of the comments) - this will identify which finger the movement data in the aforementioned event object's position array at index 'i' is associated with. Working example:

for (int i = 0; i < tPointerCount; i++) {
    int tempPointInd = event.getPointerId(i);
    if (mLastTouchX[tempPointInd] != event.getX(i) || mLastTouchY[tempPointInd] != event.getY(i)) {
        mLastTouchX[tempPointInd] = event.getX(i);
        mLastTouchY[tempPointInd] = event.getY(i);
        tActionIndex = tempPointInd;
        break;
    }
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .