在下面的类中实现带有屏幕限制的 Imageview Rotation
Posted
技术标签:
【中文标题】在下面的类中实现带有屏幕限制的 Imageview Rotation【英文标题】:Implement Imageview Rotation with screen limit in the below class 【发布时间】:2016-02-25 18:09:57 【问题描述】:我正在开发一个用于图像缩放、拖动、旋转到屏幕限制之外的 android 应用程序。首先,我必须以编程方式使图像适合整个屏幕,并对图像执行缩放、旋转、拖动操作到屏幕边界之外。我使用了以下代码,一切正常,我需要 除了旋转功能。我混淆了矩阵计算,所以请帮助任何人如何使用此代码实现旋转功能。
Java代码:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class ZoomableImageView extends ImageView
Matrix matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
int mode = NONE;
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 4f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public ZoomableImageView(Context context, AttributeSet attr)
super(context, attr);
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View v, MotionEvent event)
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction())
//when one finger is touching
//set the mode to DRAG
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
//when two fingers are touching
//set the mode to ZOOM
case MotionEvent.ACTION_POINTER_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = ZOOM;
break;
//when a finger moves
//If mode is applicable move image
case MotionEvent.ACTION_MOVE:
//if the mode is ZOOM or
//if the mode is DRAG and already zoomed
if (mode == ZOOM || (mode == DRAG && saveScale > minScale))
float deltaX = curr.x - last.x;// x difference
float deltaY = curr.y - last.y;// y difference
float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale
float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale
//if scaleWidth is smaller than the views width
//in other words if the image width fits in the view
//limit left and right movement
if (scaleWidth < width)
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
//if scaleHeight is smaller than the views height
//in other words if the image height fits in the view
//limit up and down movement
else if (scaleHeight < height)
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
//if the image doesnt fit in the width or height
//limit both up and down and left and right
else
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
//move the image with the matrix
matrix.postTranslate(deltaX, deltaY);
//set the last touch location to the current
last.set(curr.x, curr.y);
break;
//first finger is lifted
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
// second finger is lifted
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
setImageMatrix(matrix);
invalidate();
return true;
);
@Override
public void setImageBitmap(Bitmap bm)
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
public void setMaxZoom(float x)
maxScale = x;
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
@Override
public boolean onScaleBegin(ScaleGestureDetector detector)
mode = ZOOM;
return true;
@Override
public boolean onScale(ScaleGestureDetector detector)
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale)
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
else if (saveScale < minScale)
saveScale = minScale;
mScaleFactor = minScale / origScale;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height)
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1)
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
if (Math.round(origWidth * saveScale) < width)
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
else
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
else
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
return true;
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = width / bmWidth;
float scaleY = height / bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = height - (scale * bmHeight) ;
redundantXSpace = width - (scale * bmWidth);
redundantYSpace /= 2;
redundantXSpace /= 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
【问题讨论】:
旋转任何角度或只旋转您想要的特定角度?? @Aashvi 我需要旋转任意角度 【参考方案1】:您应该使用 Matrix 来做到这一点,就像您已经在做的那样,只需使用 postRotate 方法。
例子:
Matrix matrix = new Matrix();
imageView.setScaleType(ImageView.ScaleType.MATRIX);
matrix.postRotate((float) angle, pivotX, pivotY);
imageView.setImageMatrix(matrix);
希望这会有所帮助。
【讨论】:
对于旋转,此代码运行良好。我需要为上面的代码应用旋转而不影响其他功能,如放大、缩小、拖动。所以我必须在哪里应用这段代码。 你应该使用与缩放相同的矩阵,当你想旋转时调用 postRotate。 当用户用两根手指使用时,我需要旋转任意角度。我必须在我的代码中应用此代码。【参考方案2】:只需在您的代码中添加此方法
public void rotateImage(int degrees, Bitmap mBitmap)
if (mBitmap != null)
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap bitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
setImageBitmap(bitmap);
mDegreesRotated += degrees;
mDegreesRotated = mDegreesRotated % 360;
【讨论】:
以上代码在我们应用度数时有效。但是当用户使用像缩放过程这样的两个手指时,我需要在任何角度上旋转。所以请让我知道我必须在 onTouchListener 中应用旋转代码的位置。以上是关于在下面的类中实现带有屏幕限制的 Imageview Rotation的主要内容,如果未能解决你的问题,请参考以下文章
将 imageview 限制为 10% 的区域,顶部和前锚之间有空间