Android 4.3 ImageView 与 ScaleType: MATRIX
Posted
技术标签:
【中文标题】Android 4.3 ImageView 与 ScaleType: MATRIX【英文标题】:Android 4.3 ImageView with ScaleType: MATRIX 【发布时间】:2013-08-03 19:06:40 【问题描述】:我的问题最类似于:
android 4.3 ImageView ScaleType.MATRIX
还有回声:
android zoom image using matrix
但是,使用这些答案的解决方案解决了我的问题。
我正在使用 Mike Ortiz 的 TouchImageView 的修改版本,以允许双击和常规缩放手势来缩放我的 ImageView。对于Android 4.2.2及更低版本,注释掉“setScaleType(ScaleType.MATRIX)”就可以了,图片在ImageView中居中,可以随意放大缩小。但是,取消注释会导致 ImageView 的图像大小不正确。这一切都很好,因为我刚刚留下那行评论,一切正常。
但是,从 Android 4.3 开始,您无法在没有 setScaleType(ScaleType.MATRIX) 的情况下进行缩放。所以我不得不取消注释该行,但我从未解决的老问题又回来了。
那么,首先,当我所做的只是设置 ScaleType 时,为什么我的计算无法产生正确的图像/ImageView 比率?其次,为什么它会在 4.2.2 上放大而不设置比例类型,但在 4.3 上却不会?最后,有人可以给我一些资源来了解更多关于 ScaleType.MATRIX 的真正作用吗?我已经阅读了一些资料,并进行了一些谷歌搜索,但并没有完全掌握。
提前谢谢你,代码如下。
public class TouchImageView extends ImageView
Matrix matrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 10f;
float[] floatArray;
float unusedWidth, unusedHeight;
float imageViewWidth, imageViewHeight;
float initialScale = 1f;
float right, bottom, origWidth, origHeight, imageWidth, imageHeight;
boolean zoomedInLastTime = false;
PointF zoomCenter;
ScaleGestureDetector mScaleDetector;
GestureDetector mDetector;
Context context;
public TouchImageView(Context context)
super(context);
sharedConstructing(context);
public TouchImageView(Context context, AttributeSet attrs)
super(context, attrs);
sharedConstructing(context);
private void sharedConstructing(Context context)
super.setClickable(true);
this.context = context;
setScaleType(ScaleType.MATRIX);
//matrix = this.getImageMatrix();
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
//this is an empty GestureDetector
mDetector = new GestureDetector(this.context, new GestureDetector.OnGestureListener()
@Override
public boolean onDown(MotionEvent motionEvent)
return false;
@Override
public void onShowPress(MotionEvent motionEvent)
@Override
public boolean onSingleTapUp(MotionEvent motionEvent)
return false;
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2)
return false;
@Override
public void onLongPress(MotionEvent motionEvent)
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2)
return false;
, null, true);
mDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener()
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent)
return false;
@Override
public boolean onDoubleTap(MotionEvent motionEvent)
Log.d("TouchImageView", "double tap heard");
PointF currentTapLocation = new PointF(motionEvent.getX(), motionEvent.getY());
if (!zoomedInLastTime)
(new ScaleListener()).scaleIt(3f,currentTapLocation.x,currentTapLocation.y);
zoomCenter = currentTapLocation;
zoomedInLastTime = true;
else
(new ScaleListener()).scaleIt(.33f, zoomCenter.x, zoomCenter.y);
zoomedInLastTime = false;
return true;
@Override
public boolean onDoubleTapEvent(MotionEvent motionEvent)
return false;
);
matrix.setTranslate(1f, 1f);
floatArray = new float[9];
setImageMatrix(matrix);
setOnTouchListener(new DoubleTapPinchZoomListener());
@Override
public void setImageBitmap(Bitmap bm)
super.setImageBitmap(bm);
if(bm != null)
if (Build.VERSION.SDK_INT > 17)
imageWidth = bm.getWidth();
imageHeight = bm.getHeight();
else
imageWidth = 2*bm.getWidth();
imageHeight = 2*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();
scaleIt(mScaleFactor, detector.getFocusX(), detector.getFocusY());
return true;
public void scaleIt(float mScaleFactor, float focusx, float focusy)
float origScale = initialScale;
initialScale *= mScaleFactor;
if (initialScale > maxScale)
initialScale = maxScale;
mScaleFactor = maxScale / origScale;
else if (initialScale < minScale)
initialScale = minScale;
mScaleFactor = minScale / origScale;
right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
if (origWidth * initialScale <= imageViewWidth || origHeight * initialScale <= imageViewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, imageViewWidth / 2, imageViewHeight / 2);
if (mScaleFactor < 1)
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
if (Math.round(origWidth * initialScale) < imageViewWidth)
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, focusx, focusy);
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[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);
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
imageViewWidth = MeasureSpec.getSize(widthMeasureSpec);
imageViewHeight = MeasureSpec.getSize(heightMeasureSpec);
/*RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageViewWidth, imageViewHeight);
//draw the image in the view
matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);*/
//Fit to screen.
float scale;
float scaleX = (float) imageViewWidth / (float)(imageWidth);
float scaleY = (float) imageViewHeight / (float)(imageHeight);
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
initialScale = 1f;
// Center the image
unusedHeight = (float) imageViewHeight - (scale * (float) imageHeight) ;
unusedWidth = (float) imageViewWidth - (scale * (float) imageWidth);
unusedHeight /= (float)2;
unusedWidth /= (float)2;
matrix.postTranslate(unusedWidth, unusedHeight);
origWidth = imageViewWidth - 2 * unusedWidth;
origHeight = imageViewHeight - 2 * unusedHeight;
right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
setImageMatrix(matrix);
class DoubleTapPinchZoomListener implements OnTouchListener
@Override
public boolean onTouch(View v, MotionEvent event)
mScaleDetector.onTouchEvent(event);
mDetector.onTouchEvent(event);
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * initialScale);
float scaleHeight = Math.round(origHeight * initialScale);
if (scaleWidth < imageViewWidth)
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
else if (scaleHeight < imageViewHeight)
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + 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);
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
setImageMatrix(matrix);
invalidate();
return true;
【问题讨论】:
你找到答案了吗 @TerrilThomas 是的,我做到了。我将图像文件放在 res > drawable 中,而不是 res > drawable-nodpi。结果,android 不知道不自动缩放它,所以虽然我所有的计算都是正确的,但它又被缩放了,这把事情搞砸了。我将创建一个答案,并在下周左右接受它。 【参考方案1】:事实证明,这个问题与 MATRIX 缩放无关,尽管这对我来说仍然是个谜。问题是“自动”重新缩放。我已将图像放在“可绘制”文件夹中,Android 会自动缩放以“最适合屏幕尺寸”。有关这方面的更多信息,请参见此处:
http://developer.android.com/guide/practices/screens_support.html#support
解决方案是将图像放在 drawable-nodpi 中。这告诉 Android 不要根据屏幕大小重新缩放,因此,手动操作缩放不会与 Android 自己的缩放冲突。
【讨论】:
以上是关于Android 4.3 ImageView 与 ScaleType: MATRIX的主要内容,如果未能解决你的问题,请参考以下文章
ANDROID_MARS学习笔记_S01_006ImageView
?attr/selectableItemBackgroundBorderless 在工具栏 Android Studio 内的 ImageView 中不起作用
Android课程---Android ImageView的scaleType属性与adjustViewBounds属性(转)