scaleGestureDetector.getScaleFactor() always returning 1.0 in Android 6.0

我的未来我决定 提交于 2019-12-23 17:25:14

问题


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);
}

}

回答1:


I think onInterceptTouchEvent did't called. You need override onTouchEvent in your TouchableWrapper class like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    mScaleGestureDetector.onTouchEvent(event);
    return true;
}



回答2:


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.



来源:https://stackoverflow.com/questions/39594539/scalegesturedetector-getscalefactor-always-returning-1-0-in-android-6-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!