Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 当添加图像平移/拖动限制时,画布会抖动并表现不正常_Android_Math_Android Custom View - Fatal编程技术网

Android 当添加图像平移/拖动限制时,画布会抖动并表现不正常

Android 当添加图像平移/拖动限制时,画布会抖动并表现不正常,android,math,android-custom-view,Android,Math,Android Custom View,我已经做了自定义的ImageView,它可以缩放和平移。问题在于平移/拖动边界,我试图通过限制左上边缘来限制边界,如果它低于零或负值。当我这样做的时候,它会一直工作,直到其中一个条件出现,比如X变成0或者Y变成0,如果两者都变成0,它会变得急促,并且会发生一些奇怪的行为,即使小于零的条件出现,它也会越界 代码中的注释很容易理解,请帮助 这是密码 package com.example.customView; import android.content.Context; import andr

我已经做了自定义的ImageView,它可以缩放和平移。问题在于平移/拖动边界,我试图通过限制左上边缘来限制边界,如果它低于零或负值。当我这样做的时候,它会一直工作,直到其中一个条件出现,比如X变成0或者Y变成0,如果两者都变成0,它会变得急促,并且会发生一些奇怪的行为,即使小于零的条件出现,它也会越界

代码中的注释很容易理解,请帮助

这是密码

package com.example.customView;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.Camera.PreviewCallback;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;

/* @description : Custom View Zoom
 *
 */

public class ZoomView extends ImageView {

    // Maximum and Minimum Zoom
    private static float MIN_ZOOM = 1.0f;
    private static float MAX_ZOOM = 3.0f;

    //Different Operation to be used
    private final int NONE_OPERATION=0;
    private final int DRAG_OPERATION=1;
    private final int ZOOM_OPERATION=2;
    private float mWidth= 1047;
    private float mHeight=800;
    private boolean dragged=true;

    // Mode to select the operation
    private int mode;

    //Track X and Y coordinate of the finger when it first touches the screen
    private float mInitialX = 0f;
    private float mInitialY = 0f;

    //Track the amount to translate(Drag) the canvas along the X and the Y coordinate
    private float mTranslateX = 0f;
    private float mTranslateY = 0f;

    //Track the last translated X and the Y coordinate while panning so that canvas does not get the jerk (Issue was happening when we change the position again and again )
    private float mPreviousTranslateX = 0f;
    private float mPreviousTranslateY = 0f;

    //ScalingFactor i.e. Amount of Zoom
    private float mScaleFactor = 1.0f;
    float gx=0,gy=0;
    private Rect rect ;
    private Matrix matrix;


    private ScaleGestureDetector mDetector;


    // Called if used from code
    public ZoomView(Context context) {
            super(context);
        // Intialize ScaleGestureDetector
        mDetector = new ScaleGestureDetector(context, new ZoomListener());
        rect= new Rect();
        Matrix matrix= new Matrix();
    }

    //Called if used from XML
    public ZoomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDetector = new ScaleGestureDetector(context, new ZoomListener());
        rect= new Rect();
        Matrix matrix= new Matrix();
    }


    //handle the touch event of the view with the detector to get the scalingFactor and also keep the track of
    // the touch events like drag and zoom event using booleans
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // Handles all type of motion-events possible
        switch(event.getAction() & MotionEvent.ACTION_MASK) {

        case MotionEvent.ACTION_DOWN:
            // Event occurs when the first finger is pressed on the Screen

            // setting the mode to Drag Operation
            mode = DRAG_OPERATION;

            // Store the initial X and Y of the first finger when touches on the Screen. Take the difference with the previous translation so as to avoid the jerk in canvas.
            //Initial difference will be X and Y since previousTranslation will be ZERO.
            mInitialX = event.getX() - mPreviousTranslateX;
            mInitialY = event.getY() - mPreviousTranslateY;

            break;
        case MotionEvent.ACTION_MOVE:
            // Event occurs when the finger move across the screen and also when the finger is kept pressed on the screen

            // Update the translate value constantly as the event is occured at every move
            mTranslateX = event.getX() - mInitialX;                // Translate value is calculated by diff from current and initial
            mTranslateY = event.getY() - mInitialY; 

        /*    float [] matrixValues = new float[9];
            matrix.getValues(matrixValues);
            if (mode == DRAG_OPERATION) {

                if(rect.left<0 || matrixValues[Matrix.MTRANS_X]<0)
                    mTranslateX = mPreviousTranslateX;
                else
                mTranslateX = event.getX() - mInitialX;                // Translate value is calculated by diff from current and initial
                if(rect.top<0 || matrixValues[Matrix.MTRANS_Y]<0 )
                    mTranslateY=mPreviousTranslateY;
                else
                mTranslateY = event.getY() - mInitialY;


                        }*/


        //    Log.d("Print", " TranslateX::" + mTranslateX + " Translate Y::" + mTranslateY);

            // If finger is kept pressed it will still consider the move so to avoid that use this value
            //Initial X and Initial Y can not be used directly because they were adjusted  using the previous translation values. So need to add those
            // values to InitialX and InitialY so that the actual coordinates of the finger are retrieved.
            // Using distance Forumla
            double distance = Math.sqrt(Math.pow(event.getX() - (mInitialX + mPreviousTranslateX), 2) + Math.pow(event.getY() - (mInitialY + mPreviousTranslateY), 2));
                if(distance > 0) {
            dragged = true;

            }



            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            //Event occurs when the second finger is pressed down


            // If second finger is pressed on the screen with the first set the Mode to Zoom operation
            mode=ZOOM_OPERATION;

            break;

        case MotionEvent.ACTION_UP:
            //Event occurs when all the finger are taken of the screen

            //If all the fingers are taken up there will be no operation
            mode = NONE_OPERATION;
            dragged= false;
            // All the operations are done.Store the previousTranslate value here. ( Might not need at the time of second finger down ??)
            mPreviousTranslateX = mTranslateX;
            mPreviousTranslateY = mTranslateY;

            break;

        case MotionEvent.ACTION_POINTER_UP:
            // Event occurs when the second finger is taken of the screen while first finger is pressed


            // Second finger is taken up stop zooming and again Drag Operation
            mode=DRAG_OPERATION;
            break;
        }

        // give the event to the mDetector to get the scaling Factor
        mDetector.onTouchEvent(event);

        //We need to invalidate the canvas to redraw itself for the changes.Here we need to invalidate only when zoom is done and drag operation has happened
        //or else for the Zoom which was happening in the onScale function
        if((mode==DRAG_OPERATION && mScaleFactor!=1f && dragged ) || mode==ZOOM_OPERATION)
        {

            invalidate();
        }



        // we are handling the touch event
        return true;
    }




    //Everything that is going to reflect on the screen will happen in on draw
    @Override
    protected void onDraw(Canvas canvas) {

    //Save the canvas to set the scaling factor returned from detector
        canvas.save();
        canvas.scale(mScaleFactor, mScaleFactor,gx,gy);
        Log.d("Print", "mScaleFactor::" + (mScaleFactor));                 //- 1) * mWidth );
        Log.d("Print", " mTranslateX::" + mTranslateX + " mTranslateY::" +  mTranslateY);
        Log.d("Print", " ::" + mTranslateX/mScaleFactor + " mTranslateY::" +  mTranslateY/mScaleFactor);


        float[] matrixValues = new float[9] ;

    //Check the bound that we never pan past the top of left edge of the
/*    if((mTranslateX) < 0) {
        mTranslateX=0;

    }
    ////Check the right bound.
    // eg : Height of display is 1280. When it is zoom by 2 it is 1280 . when it is zoom by 3 it is  2560
    // Compare translateX times -1 to (scaleFactor - 1) * displayWidth.
    //If translateX is greater than that value, then it has gone over the bound. So we set the value of translateX to (1 - scaleFactor) times the display width.
    // Notice that the terms are interchanged... it's the same as doing -1 * (scaleFactor - 1) * displayWidth
    else if((mTranslateX) > (mScaleFactor - 1) * mWidth){
        mTranslateX=(mScaleFactor - 1 )* mWidth;
        Log.d("Print", " InDraw mTranslateX::" + mTranslateX);
    }

    if((mTranslateY)< 0)
        mTranslateY=0;
    else if((mTranslateY) > (mScaleFactor - 1) * mHeight)
        mTranslateY= (mScaleFactor-1)* mHeight;*/


        if(rect.left<0 || matrixValues[Matrix.MTRANS_X]<0)
            mTranslateX = mPreviousTranslateX;
        else
        mTranslateX = mTranslateX;                // Translate value is calculated by diff from current and initial
        if(rect.top<0 || matrixValues[Matrix.MTRANS_Y]<0 )
            mTranslateY=mPreviousTranslateY;
        else
        mTranslateY = mPreviousTranslateY;

    //divide by the scale factor here,
    //otherwise it will end up with excessive panning based on our zoom level since the translation amount also gets scaled according to how much we've zoomed into the canvas.
      canvas.translate(mTranslateX / mScaleFactor, mTranslateY / mScaleFactor);   

    // Draw anything more if needed here ....

      // Restore the canvas to balance the save Canvas which removes all the last modification before save.


      super.onDraw(canvas);

      canvas.getClipBounds(rect);
       Log.d("Print", " Canvas X::" + rect.left + " CanvasY::" + rect.top );


      matrix = canvas.getMatrix();


      Matrix m = new Matrix();
       m = canvas.getMatrix();
       float[] arr = new float[9] ;
        m.getValues(arr );
       Log.d("Print", " CanvasMatrixX::" + arr[Matrix.MTRANS_X] + " CanvasMatrixY::" + arr[Matrix.MTRANS_Y] );

        canvas.restore();
    }






/* @name : ZoomListener
 * @description : Class which defines the listener for ScaleGestureDetector while extending abstract
 *
 */
    private class ZoomListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

/*
 * ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 *
 * @description: Method gives the scaleFactor from the detector
 *
 * ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 */
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // getting the scaleFactor from the detector
            mScaleFactor *= detector.getScaleFactor();                // gives the scaling factor from the previous scaling to the current
            Log.d("Print", "detector scaling Factor" + mScaleFactor);


            gx = detector.getFocusX();
            gy = detector.getFocusY();

            // Limit the scale factor in the MIN and MAX bound
            mScaleFactor= Math.max(Math.min(mScaleFactor, MAX_ZOOM),MIN_ZOOM);
            Log.d("Print", "Bounded scaling Factor" + mScaleFactor);

            /*//Force canvas to redraw itself only if the one event is to happen (say Zooming only ) else do not invalidate here for multi operations
               As what we de for scrolling or panning will not reflect here. So we will add this in onDraw method
            invalidate();*/

            // we have handle the onScale
            return true;
        }

        @Override
            public void onScaleEnd(ScaleGestureDetector detector) {

                super.onScaleEnd(detector);
            }
    }
}
package com.example.customView;
导入android.content.Context;
导入android.graphics.Canvas;
导入android.graphics.Matrix;
导入android.graphics.Rect;
导入android.hardware.Camera.PreviewCallback;
导入android.util.AttributeSet;
导入android.util.Log;
导入android.view.MotionEvent;
导入android.view.scalegestruedetector;
导入android.widget.ImageView;
/*@description:自定义视图缩放
*
*/
公共类ZoomView扩展了ImageView{
//最大和最小缩放
私有静态浮动最小缩放=1.0f;
私有静态浮动最大缩放=3.0f;
//要使用的不同操作
私有最终int NONE_运算=0;
私有最终整数拖动操作=1;
私有最终整数缩放操作=2;
私人浮动mWidth=1047;
私人浮点数mhweight=800;
私有布尔值=真;
//模式来选择操作
私有int模式;
//第一次触摸屏幕时跟踪手指的X和Y坐标
专用浮点数mInitialX=0f;
私有浮动最小=0f;
//跟踪沿X和Y坐标平移(拖动)画布的量
私人浮动MTRANSE=0f;
私有浮动mTranslateY=0f;
//平移时跟踪上一次平移的X和Y坐标,以便画布不会受到冲击(当我们一次又一次地更改位置时,问题就发生了)
私人浮动mPreviousTranslateX=0f;
私人浮动mPreviousTranslateY=0f;
//缩放因子,即缩放量
私人浮动mScaleFactor=1.0f;
浮动gx=0,gy=0;
私人直肠;
私有矩阵;
私有scalegestruedetector mDetector;
//如果从代码中使用,则调用
公共ZoomView(上下文){
超级(上下文);
//初始化scalegestruedetector
mDetector=new ScaleGestureDetector(上下文,new ZoomListener());
rect=新的rect();
矩阵=新矩阵();
}
//如果从XML使用,则调用
公共ZoomView(上下文、属性集属性){
超级(上下文,attrs);
mDetector=new ScaleGestureDetector(上下文,new ZoomListener());
rect=新的rect();
矩阵=新矩阵();
}
//使用探测器处理视图的触摸事件,以获得缩放因子,并跟踪
//触摸事件,如使用布尔值的拖动和缩放事件
@凌驾
公共布尔onTouchEvent(运动事件){
//处理所有类型的运动事件
开关(event.getAction()&MotionEvent.ACTION\u掩码){
case MotionEvent.ACTION\u DOWN:
//在屏幕上按下第一个手指时发生事件
//将模式设置为拖动操作
模式=拖动操作;
//当触摸屏幕时,存储第一个手指的初始X和Y。将其与之前的翻译进行差异,以避免画布上的抖动。
//初始差值为X和Y,因为之前的平移为零。
mInitialX=event.getX()-mPreviousTranslateX;
mInitialY=event.getY()-mPreviousTranslateY;
打破
case MotionEvent.ACTION\u移动:
//事件发生在手指在屏幕上移动时,以及手指一直按在屏幕上时
//在每次移动时发生事件时,不断更新转换值
mtransletase=event.getX()-mInitialX;//转换值由当前值和初始值的差值计算
mTranslateY=event.getY()-mInitialY;
/*浮动[]矩阵值=新浮动[9];
矩阵。获取值(矩阵值);
如果(模式==拖动操作){

如果(rect.left我认为问题是因为您不必要地使视图无效(即使在限制之后)。您应该检查
onTouch
本身的边界,并决定是否重新绘制视图。一旦达到限制,您应该停止重绘

检查
onTouch
方法中
mtransletase
的值,并调用invalidate

...
if (mTranslateX >= 0 || mTranslateY >= 0) {
    invalidate();
}

if (mTranslateX < 0)
    mTranslateX = 0;
if (mTranslateY < 0)
    mTranslateY = 0;
...
。。。
如果(mTranslateY>=0 | | mTranslateY>=0){
使无效();
}
if(mtransletex<0)
mtransletase=0;
如果(mTranslateY<0)
mTranslateY=0;
...

你能给出这种奇怪行为的截图吗?@a.ch.当它被缩放时,我尝试从左上角向下平移它..当我的bg图像被向下拖动..同时来到(0,0)也就是说,左上角,直到那个时候它还可以,但一旦它变成负片,它就会变成矩形。左上角和矩形。在这里,它与x和y一起播放。我的意思是抽搐…抽搐意味着有时它在x轴上,有时在y轴上…像那样…希望你得到了…如何显示舞蹈图像的屏幕截图…我确实尝试过保持if(rect.left>=0 | | rect.top>=0){isTranslate=true;还有一个条件,我正在执行invalidate()若它是真的,那个么只有它会失效,否则不会,但它仍然不起作用。不必要的失效似乎是这里唯一的问题。你们需要再次检查你们的if条件..添加mtranslateX,mtranslateY到它。。