2012-12-19 58 views
9

我的应用程序有点问题。我刚刚实施了缩放缩放,但是当我缩小变焦时,图像不会缩放在下面图像中显示的2个点的中心。图像1是我的手指在捏之前的位置,图像2是要显示它没有缩放到我手指的中心位置。Android SDK - 在触摸中心不缩放

图片1对图2:
image1image2

这里是我的代码:

 package com.jpiionefourone.guitarimage; 

    import android.content.Context; 
    import android.graphics.Canvas; 
    import android.graphics.drawable.Drawable; 
    import android.util.AttributeSet; 
    import android.view.MotionEvent; 
    import android.view.ScaleGestureDetector; 
    import android.view.View; 

    public class MultiTouchView extends View { 
     private Drawable mIcon; 
     private float mPosX; 
     private float mPosY; 

     private float mLastTouchX; 
     private float mLastTouchY; 

     private static final int INVALID_POINTER_ID = -1; 

     // The ‘active pointer’ is the one currently moving our object. 
     private int mActivePointerId = INVALID_POINTER_ID; 

     private ScaleGestureDetector mScaleDetector; 
     private float mScaleFactor = 1.f; 


     public MultiTouchView(Context context) { 
      this(context, null, 0); 
     } 

     public MultiTouchView(Context context, AttributeSet attrs) { 
      this(context, attrs, 0); 
     } 

     public MultiTouchView(Context context, AttributeSet attrs, int defStyle) { 
      super(context, attrs, defStyle); 
      mIcon = context.getResources().getDrawable(R.drawable.guitar); 
      mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight()); 

      // Create our ScaleGestureDetector 
      mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 

     } 

     @Override 
     public boolean onTouchEvent(MotionEvent ev) { 
      // Let the ScaleGestureDetector inspect all events. 
      mScaleDetector.onTouchEvent(ev); 

      final int action = ev.getAction(); 
      switch (action & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: { 
       final float x = ev.getX(); 
       final float y = ev.getY(); 

       mLastTouchX = x; 
       mLastTouchY = y; 
       mActivePointerId = ev.getPointerId(0); 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: { 
       final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
       final float x = ev.getX(pointerIndex); 
       final float y = ev.getY(pointerIndex); 

       // Only move if the ScaleGestureDetector isn't processing a gesture. 
       if (!mScaleDetector.isInProgress()) { 
        final float dx = x - mLastTouchX; 
        final float dy = y - mLastTouchY; 

        mPosX += dx; 
        mPosY += dy; 

        invalidate(); 
       } 

       mLastTouchX = x; 
       mLastTouchY = y; 

       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_CANCEL: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_UP: { 
       final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
         >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = ev.getPointerId(pointerIndex); 
       if (pointerId == mActivePointerId) { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        mLastTouchX = ev.getX(newPointerIndex); 
        mLastTouchY = ev.getY(newPointerIndex); 
        mActivePointerId = ev.getPointerId(newPointerIndex); 
       } 
       break; 
      } 
      } 

      return true; 
     } 

     @Override 
     public void onDraw(Canvas canvas) { 
      super.onDraw(canvas); 

      canvas.save(); 
      canvas.translate(mPosX, mPosY); 
      canvas.scale(mScaleFactor, mScaleFactor); 
      mIcon.draw(canvas); 
      canvas.restore(); 
     } 

     private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
      @Override 
      public boolean onScale(ScaleGestureDetector detector) { 
       mScaleFactor *= detector.getScaleFactor(); 

       // Don't let the object get too small or too large. 
       mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); 

       invalidate(); 
       return true; 
      } 
     } 
    } 

感谢,

贾里德

回答

10

在你ScaleListener类,你只能调整mScaleFactor所以,确实,你的图像确实会不是放大你的多点触摸手势的中心!

此外,您需要更新mPosXmPosY以使用不同的缩放中心。

对于我自己的应用程序之一,我用的是这样的:

final float scale = detector.getScaleFactor(); 
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor * scale, 5.0f)); 

if (mScaleFactor < 5f) { 
    // 1 Grabbing 
    final float centerX = detector.getFocusX(); 
    final float centerY = detector.getFocusY(); 
    // 2 Calculating difference 
    float diffX = centerX - mPosX; 
    float diffY = centerY - mPosY; 
    // 3 Scaling difference 
    diffX = diffX * scale - diffX; 
    diffY = diffY * scale - diffY; 
    // 4 Updating image origin 
    mPosX -= diffX; 
    mPosY -= diffY; 
} 

基本上,它计算出

  1. 抓住你多起源图像起源的相对变化触摸手势(getFocus()
  2. 计算图像原点之间的差异(diffXdiffY
  3. 应用比例因子
  4. ,通过使用比例差异

这(仍)适用于我的情况更新图像的起源。我不知道我们是否都使用(d)相同的坐标系,但像这样的东西应该可以帮助您正确缩放多点触控手势中心的图像。

1

我花了很长时间才得到这个工作..但是,感谢几乎工作的代码!我不知道是我只是搞乱了或者只是在代码中进行了这些更改,我得到了我想要的缩放工作!希望这会让某些人安全。

mScaleFactor *= detector.getScaleFactor(); 
mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 3.0f)); 
scale = mScaleFactor/scaleAtm 


mTranslateMatrix.preTranslate(diffX, diffY); 
mTranslateMatrix.invert(mTranslateMatrixInverse); 
mPosX += diffX; 
mPosY += diffY; 
scaleAtm = mScaleFactor; 

起初scaleAtm = 1

+0

不,不会。因为你的代码丢失了。什么是scaleAtm?你在哪里使用mTranslateMatrix? –

+0

嘿,即时通讯使用有点不同缩放方式,因为我想能够在缩放后拖动所有内容。你可以找到我在这里使用的方式 http://stackoverflow.com/questions/12479859/view-with-horizo​​ntal-and-vertical-pan-drag-and-pinch-zoom/12497670#12497670 – niksi