我正在修改TouchImageView (https://github.com/MikeOrtiz/TouchImageView/issues),以便在双击时放大和缩小。我已经开始按照这篇文章-如何TouchImageView工作?并添加了手势检测。
现在我必须实现放大和缩小,我不知道该怎么做。以下是我到目前为止使用未实现的zoomIn和zoomOut方法的代码。有人知道怎么做吗?此外,我注意到缩放缩放并没有真正缩放到你缩放的位置,所以我希望这可以更像gallery3D缩放缩放。谢谢。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
private static final String TAG = TouchImageView.class.getSimpleName();
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 = 3f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
private GestureDetector gestureDetector;
Context context;
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public TouchImageView(Context context) {
super(context);
init(context);
}
public void init(Context context) {
gestureDetector = new GestureDetector(new DoubleTapGestureListener());
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) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
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()) {
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 * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
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_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;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
@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 SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
LogUtil.i(TAG, detector.getScaleFactor() + " " + detector.getFocusX() + " " + detector.getFocusY());
float mScaleFactor = (float) Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05);
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 = (float) width / (float) bmWidth;
float scaleY = (float) height / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = (float) height - (scale * (float) bmHeight);
redundantXSpace = (float) width - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 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);
}
class DoubleTapGestureListener extends SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
float x = e.getX();
float y = e.getY();
LogUtil.i(TAG, "Tapped at: (" + x + "," + y + ")");
if (isZoomed()) {
zoomOut();
} else {
zoomIn();
}
return true;
}
}
public boolean isZoomed() {
return saveScale > minScale; // this seems to work
}
public void zoomIn() {
LogUtil.i(TAG, "Zooming in");
// TODO: no idea how to do this
}
public void zoomOut() {
LogUtil.i(TAG, "Zooming out");
// TODO: no idea how to do this
}
}
我的答案可能不是完全针对您的问题,但它涵盖了ImageView缩放,双击,ImageView缩放时的边界图像,总之就像Android的默认Gallery应用程序
http://blog.sephiroth.it/2011/04/04/imageview-zoom-and-scroll/正如博客所说:
只要Android没有内置的带有缩放和滚动功能的ImageView小部件,我就尝试自己从google库开始创建一个。
结果很好,所以我在这里张贴源代码,如果每个人都感兴趣,或者只是不想浪费时间创建新文件
将当前缩放倍率放大,然后返回到原始缩放级别:
float oldScale = 1.0f;
public void zoomIn() {
LogUtil.i(TAG, "Zooming in");
oldScale = saveScale;
saveScale *= 2;
matrix.setScale(saveScale, saveScale);
setImageMatrix(matrix);
invalidate();
}
public void zoomOut() {
LogUtil.i(TAG, "Zooming out");
saveScale = oldScale;
matrix.setScale(saveScale, saveScale);
setImageMatrix(matrix);
invalidate();
}
您可能希望将矩阵转换到用户双击的点的中心
@sherlock,
如果您想在再次双击时缩小,您可以编写如下方法:
private void handleScaleWhenDoubleTap(float scaleFactor) {
//set original scale
float origScale = curScale;
//update current scale
curScale *= scaleFactor;
//fix current scale if it greater than max scale, recalculate scale factor
if (curScale > maxScale) {
curScale = maxScale;
scaleFactor = maxScale / origScale;
}
//fix current scale if it less than min scale, recalculate scale factor
else if (curScale < minScale) {
curScale = minScale;
scaleFactor = minScale / origScale;
}
//calculate right point, bottom point
right = (curScale - 1) * width - 2 * (redundantXSpace * curScale);
bottom = (curScale - 1) * height - 2 * (redundantYSpace * curScale);
//scale
matrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2);
//translate
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (y + bottom < 0) {
if (x >= 0) {
matrix.postTranslate(-x + redundantXSpace, -(y + bottom + redundantYSpace));
} else if (x + right < 0) {
matrix.postTranslate(-(x + right + redundantXSpace), -(y + bottom + redundantYSpace));
} else {
matrix.postTranslate(0, -(y + bottom));
}
} else if (y >= 0) {
if (x >= 0) {
matrix.postTranslate(-x + redundantXSpace, -y + redundantYSpace - navBarHeight);
} else if (x + right < 0) {
matrix.postTranslate(-(x + right + redundantXSpace), -y + redundantYSpace - navBarHeight);
} else {
matrix.postTranslate(0, -y);
}
} else {
if (x >= 0) {
matrix.postTranslate(-x, redundantYSpace - navBarHeight);
} else if (x + right < 0) {
matrix.postTranslate(-(x + right + redundantXSpace), redundantYSpace - navBarHeight);
} else {
matrix.postTranslate(0, -navBarHeight);
}
}
}
注意:如果手机有软导航条(如Nexus 5),你必须重新计算翻译的距离。在我的例子中,navBarHeight是由函数设置的变量:
public int getNavBarHeight(Context ctx) {
int id = ctx.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
boolean hasNavBar = id > 0 && ctx.getResources().getBoolean(id);
if (hasNavBar) {
int resourceId = ctx.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return ctx.getResources().getDimensionPixelSize(resourceId);
}
}
return 0;
}
如果有帮助请告诉我。
双击等手势可检测如下:网格布局下的Fling手势检测
我希望这有助于…伊曼纽尔
使用上面的TouchImageView类,如果你想应用双击,你可以做一些步骤:
-
声明变量:
GestureDetector mDoubleTap;
-
Init in constructor:
mDoubleTap = new GestureDetector(new DoubleTapGestureListener());
-
Register in onTouch():
@Override public boolean onTouch(View v, MotionEvent event) { mDoubleTap.onTouchEvent(event); ... }
-
编写方法handleScale() -复制自onScale()方法-如下:
private void handleScale(float mScaleFactor) { 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, mScaleDetector.getFocusX(), mScaleDetector.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); } } }
-
在 zoomIn () 方法:
public void zoomIn() { handleScale(2.0f);// 2.0f is the scale ratio }
-
在重写方法onScale()中,可以修改为:
@Override public boolean onScale(ScaleGestureDetector detector) { float mScaleFactor = detector.getScaleFactor(); handleScale(mScaleFactor); return true; }
遵循DRY原则。
注意: 双击只对小触点区域有效。
让我知道它是否适合你