Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scaleGestureDetector.getScaleFactor() always returning 1.0 in Android 6.0

I am using ScaleGestureDetector to detect pinch out and pinch in actions, by getting the scale factor an if it is less then one then it is zoom out and vise versa.

But the problem is that on Android 6.0 the scale factor is always 1.0 which make it impossible to distinguish pinch in from pinch out.

Thanks in advance for any help.

import android.content.Context;
import android.os.Handler;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.widget.FrameLayout;

public class TouchableWrapper extends FrameLayout
{
    private GestureDetectorCompat mGestureDetector;
    private ScaleGestureDetector mScaleGestureDetector;
    private VelocityTracker mVelocityTracker;
    private boolean acceptEvents=true;
    ScaleGestureDetector temp;


private final GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener()
{

    @Override
    public boolean onDoubleTap(MotionEvent e)
    {
        EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.MAP_DOUBLE_TOUCHED));
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return super.onDoubleTapEvent(e);
    }



};

private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener()
{
    /**
     * This is the active focal point in terms of the viewport. Could be a local
     * variable but kept here to minimize per-frame allocations.
     */

    float startingSpan;
    float startFocusX;
    float startFocusY;

    @Override
    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector)
    {

        temp=scaleGestureDetector;
        startingSpan = scaleGestureDetector.getCurrentSpan();
        startFocusX = scaleGestureDetector.getFocusX();
        startFocusY = scaleGestureDetector.getFocusY();

        return true;
    }

    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector)
    {
        super.onScale(scaleGestureDetector);

        float scale = scaleGestureDetector.getScaleFactor();
        //mVelocityTracker.computeCurrentVelocity(1000);



        if(acceptEvents)
        {

            Log.e("scaleGestureDetector.getCurrentSpan()", scaleGestureDetector.getCurrentSpan()+"");
            Log.e("startingSpan", startingSpan+"");
            Log.e("onScale",scale+"");

            if (scale <= 1.0)
            {
                acceptEvents = false;
                EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.MAP_ZOOMED_OUT));
            }
            else
            {
                acceptEvents = false;
                EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.MAP_ZOOMED_IN));
            }
        }

        return true;
    }
};

public TouchableWrapper(Context context)
{
    super(context);
    mScaleGestureDetector = new ScaleGestureDetector(context, mScaleGestureListener);
    mGestureDetector = new GestureDetectorCompat(context, mGestureListener);
    mVelocityTracker = VelocityTracker.obtain();
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    mGestureDetector.onTouchEvent(ev);
    //Log.e("Motion Event pointer count",ev.getPointerCount()+"");


    int action = MotionEventCompat.getActionMasked(ev);

    switch (action)
    {
        case (MotionEvent.ACTION_DOWN):
            Log.e("MotionEvent", "Action was DOWN");
            break;
        case (MotionEvent.ACTION_MOVE):
            //Log.e("MotionEvent", "Action was MOVE");
            /*if(acceptEvents)
            {
                if(MotionEventCompat.getPointerCount(ev)==2)
                {

                    x1=MotionEventCompat.getX(ev,0);
                    x2=MotionEventCompat.getX(ev,1);
                    y1=MotionEventCompat.getY(ev,0);
                    y2=MotionEventCompat.getY(ev,1);


                    if(differenceX==0||differenceY==0)
                    {
                        differenceX=Math.abs(x1-x2);
                        differenceY=Math.abs(y1-y2);
                    }
                    else
                    {
                        differenceXPrime=Math.abs(x1-x2);
                        differenceYPrime=Math.abs(y1-y2);


                        if (differenceXPrime-differenceX>100 || differenceYPrime-differenceY>100)
                        {
                            Log.e("Zoomed out","differenceX:"+differenceX+"         differenceXPrime:"+differenceXPrime+"           differenceY:"+differenceY+"            differenceYPrime:"+differenceYPrime);
                            differenceX=0;
                            differenceY=0;
                            acceptEvents=false;
                            EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.MAP_ZOOMED_IN));

                        }
                        else if(differenceX-differenceXPrime>100 || differenceY-differenceYPrime>100)
                        {
                            Log.e("Zoomed in","differenceX:"+differenceX+"         differenceXPrime:"+differenceXPrime+"           differenceY:"+differenceY+"            differenceYPrime:"+differenceYPrime);
                            differenceX=0;
                            differenceY=0;
                            acceptEvents=false;
                            EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.MAP_ZOOMED_OUT));
                        }
                    }
                }
            }*/

            break;
        case (MotionEvent.ACTION_UP):
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.ENABLE_MAP_GESTURE));
                    acceptEvents=true;
                }
            },300);

            Log.e("MotionEvent", "Action was UP");
            break;
        case (MotionEvent.ACTION_POINTER_UP):
            Log.e("MotionEvent", "Action was POINTER UP");
            break;
        case (MotionEvent.ACTION_POINTER_DOWN):
            EventBus_Singleton.getInstance().post(new EventBus_Poster(Constants.DISABLE_MAP_GESTURE));
            Log.e("MotionEvent", "Action was POINTER DOWN");
            break;
        case (MotionEvent.ACTION_CANCEL):
            Log.e("MotionEvent", "Action was CANCEL");
            break;
        case (MotionEvent.ACTION_OUTSIDE):
            Log.e("MotionEvent", "Movement occurred outside bounds of current screen element");
            break;
    }
    mVelocityTracker.addMovement(ev);
    mScaleGestureDetector.onTouchEvent(ev);
    return super.onInterceptTouchEvent(ev);
}

}
like image 260
Mohammad Haidar Avatar asked Sep 20 '16 12:09

Mohammad Haidar


1 Answers

I think the problem is that when you do the pinch gesture slowly, this class discards the small increments of span between the fingers. It only worries about large differences in span.

If you pinch slowly it will register a number of different touch moving events, each one with a span (between the fingers) only slightly different than the previous event. It considers the span didn't change thus the scale factor is 1.

If you pinch fast, it will register a larger span than the last event and will give you a factor different than 1.

In my solution I customize the class. I calculate the scale factor myself. The scale factor is 1 as long as you're not pinching. Then when you start pinching the scale factor is calculated from the beginning of the pinch gesture and not from the previous touch event.

So I make a subclass of ScaleGestureDetector and in it I override onTouchEvent(). In it I keep track of both fingers, and if both are moving I measure the start span and keep it. I override getScaleFactor() and the factor is calculated based on the current span versus the start span. When any of the fingers is removed, the scaling is finished; the factor goes back to 1.

like image 134
Emmanuel Avatar answered Oct 24 '22 14:10

Emmanuel