Search code examples
androidontouch

Consume only two finger touch


I want to catch ONLY two fingers touch (one finger touch must be NOT consumed). Unfortunately, I need to consume the "one finger touch" in order to get the "two finger touch" events. I hope I'm a clear.

Here my code :

@Override
public boolean onTouch(View v, MotionEvent m)
{
    boolean consumed = false;
    int pointerCount = m.getPointerCount();
    int action = m.getActionMasked();

    if(pointerCount == 2)
    {
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                consumed = true;

                break;
            case MotionEvent.ACTION_UP:
                // Work
                break;
            case MotionEvent.ACTION_MOVE:
                // Some stuff
                break;
            default:
                break;
        }
    }
    else if (pointerCount == 1 && action == MotionEvent.ACTION_DOWN)
    {
        // This is needed to get the 2 fingers touch events... 
        consumed = true;
    }

    return consumed;
}

Solution

  • I've ran into a similar problem and solved my problem by handling all touches at my top view, and propagating the appropriate actions to the views below. In my example, I had an overlay layer that needed to intercept scale gestures (a recognizer is attached in my constructor), while still propagating single touches to my map view below. I haven't sent the actual touch event to my map view, but I've handled it in my top view and sent the appropriate "panning" action to my view below.

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getPointerCount() == 2) {
            if(event.getActionMasked() == MotionEvent.ACTION_DOWN){
                CameraUpdate update = CameraUpdateFactory.newLatLng(initialCoords);
                //attachedMapFragment.getMap().moveCamera(update);
            }
            scaleGestureDetector.onTouchEvent(event);
        }else{
            if(attachedMapFragment != null) {
                if(event.getActionMasked() == MotionEvent.ACTION_DOWN){
                    initialCoords = attachedMapFragment.getMap().getCameraPosition().target;
                    lastTouchX = event.getX();
                    lastTouchY = event.getY();
                }else if(event.getActionMasked() == MotionEvent.ACTION_MOVE){
                    float deltaX = event.getX() - lastTouchX;
                    float deltaY = event.getY() - lastTouchY;
                    lastTouchX = event.getX();
                    lastTouchY = event.getY();
                    Projection projection = attachedMapFragment.getMap().getProjection();
                    Point center = projection.toScreenLocation(attachedMapFragment.getMap().getCameraPosition().target);
                    Point newCenter = new Point(center.x - (int)deltaX, center.y - (int)deltaY);
                    LatLng newCoords = projection.fromScreenLocation(newCenter);
                    CameraUpdate update = CameraUpdateFactory.newLatLng(newCoords);
                    attachedMapFragment.getMap().moveCamera(update);
                }
            }
        }
        return true;
    }
    

    This way, I had a scale recognizer on my custom view, while the map was still panning appropriately to single touch. Actually, map view wasn't getting any touches at all, my custom view was "routing" the action as seen above. While not always ideal, this would solve the problem in many cases.