2012-04-11 3 views
1

ズームとパンが可能なカスタムImageViewを作成しました。問題は、パン/ドラッグの境界にあります。ゼロまたはマイナス以下になると、上限を左端に付けることによって境界を制限しようとしました。私はこれをやっているとき、それはXが0になったか、その両方が、それがジャークを取得し、いくつかの奇妙な行動がゼロ未満の条件があり、それはバウンドの外に出た場合でも発生し0になった場合、Yが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); 
      } 
    } 
} 
+0

この奇妙な動作のスクリーンショットを教えてください。 –

+1

@ a.ch。何が起こっていることは、その罰金しかし、すぐにそれが行くようになるまで、すなわちTOPLEFTそれがスケーリングを取得する場合であり、私は左上からそれをパンしてみてください(0,0)に来る..while下にドラッグを取得私のBG画像を..as負にそれは時々、それはその方法のように... yの中で、時にはx軸に行く意味... uが得を願ってピクピク...ジャークを意味rect.topのconditonに行くと、それは、x番目のYIを果たし、ここrect.leftそれは..どのようにダンスイメージのスクリーンショットを表示する..? – user1201239

答えて

0

です。 onTouchの境界を確認して、ビューを再描画するかどうかを決定する必要があります。制限に達すると、再描画を停止する必要があります。

mTranslateXの値をonTouchメソッドでチェックし、無効を呼び出します。

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

if (mTranslateX < 0) 
    mTranslateX = 0; 
if (mTranslateY < 0) 
    mTranslateY = 0; 
... 
+0

私がもし(rect.left> = 0 || rect.top> = 0){isTranslate =真を保つことによってことを試してみました。そしてその真の場合、私は)(無効化をやっている条件は、それが無効か、他ではないが、それでもそれがバインドさ – user1201239

+0

不要な無効化でそれを維持すると動作しませんでしたでしょうにのみ、ここでの唯一の問題のようです。あなたはそれにmtranslateX、mtranslateYを追加... – Ronnie

+0

まず削除無効化を()...もう一度、あなたの場合は条件をチェックして、パフォーマンスが改善されるかどうかを確認する必要があります。 – Kai