2017-01-27 9 views
1

У меня есть пользовательский класс, который простирается от View, где я рисую растровое изображение и хочу сделать масштаб и перетащить его с ограничениями. Моя задача - создать ImageView, который будет использоваться в галерее, чтобы увидеть полную фотографию. Теперь я понял масштаб и сопротивление, но когда я начал понимать их ограничения, заметил, что после изменения положения изображения canvas.scale (mScale, mScale, mid.x, mid.y), но мои значения mX, mY не изменяются. Для этого я начал делать масштаб со средней точкой и вручную менять mX и mY. Поэтому у меня есть проблема с ручным изменением этих значений.Android фиксирует координаты после масштабирования холста по средней точке

Мой класс:

public class ZoomImageView2 extends View { 

private File imageFile; 
private Bitmap bitmap; 

private static final int NONE = 0; 
private static final int DRAG = 1; 
private static final int ZOOM = 2; 
private int mode = NONE; 


private PointF start = new PointF(); 
private PointF mid = new PointF(); 
private float oldDist = 1f; 
private float d = 0f; 
private float newRot = 0f; 
private float[] lastEvent = null; 

private int mX = 0, mY = 0; 
private float mScale = 1f; 

private Rect clipBounds_canvas; 

private Handler mainHadler; 

public ZoomImageView2(Context context) { 
    super(context); 
    mainHadler = new Handler(Looper.getMainLooper()); 
} 

public ZoomImageView2(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    mainHadler = new Handler(Looper.getMainLooper()); 
} 

public ZoomImageView2(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    mainHadler = new Handler(Looper.getMainLooper()); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    //super.onDraw(canvas); 
    if (bitmap != null) { 
     canvas.save(); 
     clipBounds_canvas = canvas.getClipBounds(); 
     Log.w("SCALING_ZOOMIMAGE2", mX + " " + mY + " " + mScale); 
     canvas.scale(mScale, mScale); 
     canvas.drawBitmap(bitmap, mX, mY, new Paint()); 
     canvas.restore(); 
    } 
} 

public void setImageFile(final File imageFile) { 
    this.imageFile = imageFile; 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      bitmap = BitmapHelper.getINSTANCE().getSampledBitmapFromFile(imageFile.getAbsolutePath(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().widthPixels); 
      new Handler(Looper.getMainLooper()).post(new Runnable() { 
       @Override 
       public void run() { 
        if (bitmap.getWidth() >= bitmap.getHeight()) { 
         mStableScale = (float) getResources().getDisplayMetrics().widthPixels/(float) bitmap.getWidth(); 
        } else { 
         mStableScale = (float) getResources().getDisplayMetrics().heightPixels/(float) bitmap.getHeight(); 
        } 
        mScale = mStableScale; 
        invalidate(); 
       } 
      }); 
     } 
    }).start(); 
} 

int mOldX, mOldY; 
float mOldScale = 1f; 
float mStableScale; 
float maxScale = 5f; 


@Override 
public boolean onTouchEvent(MotionEvent event) { 
    switch (event.getAction() & MotionEvent.ACTION_MASK) { 
     case MotionEvent.ACTION_DOWN: 
      start.set(event.getX(), event.getY()); 
      mode = DRAG; 
      lastEvent = null; 
      mOldX = mX; 
      mOldY = mY; 
      mOldScale = mScale; 
      break; 

     case MotionEvent.ACTION_POINTER_DOWN: 

      oldDist = spacing(event); 
      if (oldDist > 10f) { 
       midPoint(mid, event); 
       mode = ZOOM; 
      } 

      lastEvent = new float[4]; 
      lastEvent[0] = event.getX(0); 
      lastEvent[1] = event.getX(1); 
      lastEvent[2] = event.getY(0); 
      lastEvent[3] = event.getY(1); 
      break; 

     case MotionEvent.ACTION_UP: 
      if (mScale < mStableScale) { 
       animateScaleTo(false); 
      } 
      if (mScale > maxScale) { 
       animateScaleTo(true); 
      } 

     case MotionEvent.ACTION_POINTER_UP: 

      mode = NONE; 
      lastEvent = null; 
      break; 

     case MotionEvent.ACTION_MOVE: 

      if (mode == DRAG) { 
       mX = (int) ((event.getX() - start.x)/mScale + mOldX); 
       mY = (int) ((event.getY() - start.y)/mScale + mOldY); 

      } else if (mode == ZOOM) { 
       float newDist = spacing(event); 

       if (newDist > 10f) { 
        mScale = (newDist/oldDist) * mOldScale; 
        mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale); 
        mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale); 
        //TODO! 
       } 

       if (lastEvent != null && event.getPointerCount() == 3) { 

        //newRot = rotation(event); 
        //float r = newRot - d; 
        //float[] values = new float[9]; 
        //matrix.getValues(values); 
        //float tx = values[2]; 
        //float ty = values[5]; 
        //float sx = values[0]; 
        //float xc = (view.getWidth()/2) * sx; 
        //float yc = (view.getHeight()/2) * sx; 
        //matrix.postRotate(r, tx + xc, ty + yc); 

       } 
      } 
      break; 
    } 
    invalidate(); 
    return true; 
} 

private void animateScaleTo(final boolean forMax) { 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      try { 
       int waiting = 1; 
       if (forMax) { 
        waiting = (int) (100/((mScale - maxScale)/0.05)); 
       } else { 
        waiting = (int) (100/((mStableScale - mScale)/0.05)); 
       } 
       if (waiting == 0) waiting = 1; 
       while (forMax ? mScale >= maxScale : mScale <= mStableScale) { 
        if (forMax) { 
         mScale -= 0.05; 
        } else { 
         mScale += 0.05; 
        } 
        mainHadler.post(new Runnable() { 
         @Override 
         public void run() { 
          invalidate(); 
         } 
        }); 
        Thread.sleep(waiting); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }).start(); 
} 


private void animateTranslateX(final boolean forEnd) { 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      try { 
       int waiting; 
       if (forEnd) { 
        waiting = (int) (300f/(mX - (float) bitmap.getWidth() * mScale)); 
       } else { 
        waiting = (int) (300f/(float) (mX)); 
       } 
       if (waiting == 0) waiting = 1; 
       while (forEnd ? mX > ((float) bitmap.getWidth() * mScale) : mX > 0) { 
        mX -= 5; 
        mainHadler.post(new Runnable() { 
         @Override 
         public void run() { 
          invalidate(); 
         } 
        }); 
        Thread.sleep(waiting); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }).start(); 
} 

private void animateTranslateY(final boolean forEnd) { 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      try { 
       int waiting; 
       if (forEnd) { 
        waiting = (int) (300/(mY - (float) bitmap.getHeight() * mScale)); 
       } else { 
        waiting = (int) (300/(float) (mY)); 
       } 
       if (waiting == 0) waiting = 1; 
       while (forEnd ? mY > ((float) bitmap.getHeight() * mScale) : mY > 0) { 
        mY -= 5; 
        mainHadler.post(new Runnable() { 
         @Override 
         public void run() { 
          invalidate(); 
         } 
        }); 
        Thread.sleep(waiting); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }).start(); 
} 


private float spacing(MotionEvent event) { 
    float x = event.getX(0) - event.getX(1); 
    float y = event.getY(0) - event.getY(1); 
    return (float) Math.sqrt(x * x + y * y); 
} 

private void midPoint(PointF point, MotionEvent event) { 
    point.set(getResources().getDisplayMetrics().widthPixels/2, getResources().getDisplayMetrics().heightPixels/2); 
} 

}

У меня проблема в месте:

if (newDist > 10f) { 
    mScale = (newDist/oldDist) * mOldScale; 
    mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale); 
    mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale); 
     //TODO! 
    } 

Здесь я должен установить значения. Теперь это неправильно.

Я провожу много времени, чтобы решить эту проблему. Большое спасибо за помощь! Извините за плохой английский

+0

«Теперь его неправильно» - вы имеете в виду, что неправильное значение получает установленное значение, или вы видите какую-то ошибку? Что вы видите, что считаете, что ошибаетесь? –

+0

Да, неправильное значение получает заданное значение, а растровая позиция изменения неверна. – androidAnonDev

+0

Итак, правильно ли я понимаю, что вы создаете миниатюру или меньшую версию оригинальных изображений? Если нет, пожалуйста, опишите, насколько вы можете, что вы ожидаете от трансформации и что она на самом деле делает. –

ответ

1

Как обсуждалось в комментариях, часть решения заключается в следующем: Измените следующее:

mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale); 
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale); 

к:

mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 - mOldX*mScale); 
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 - mOldY*mScale); 

удалить ненужный дополнительный этап умножения , что приводит к масштабированию изображения до слишком большого размера.