java TouchImageView 是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7491519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does TouchImageView works?
提问by Tsunaze
I have good working TouchImageView and i want to know how does it work in a code : What i just want to do is be able to pinch to zoom, or use double tap to zoom on any imageview i choose, and when i zoom back i return to the original size of the image. TouchImageView.java :
我有很好的 TouchImageView 工作,我想知道它是如何在代码中工作的:我只想做的是能够捏缩放,或使用双击缩放我选择的任何图像视图,当我放大时我恢复到图像的原始大小。TouchImageView.java :
public class TouchImageView extends ImageView {
Matrix matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
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;
Context context;
public TouchImageView(Context context) {
super(context);
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()) {
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 ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
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);
}
}
To use is i created a private class :
要使用的是我创建了一个私有类:
private class CreateImage extends AsyncTask<String, Void, Drawable> {
protected void onPreExecute() {
}
protected Drawable doInBackground(String... urls) {
InputStream is;
Drawable d = null ;
try {
is = (InputStream)new URL(urls[0]).getContent();
d = Drawable.createFromStream(is, "Image");
return d;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return d;
}
protected void onPostExecute(Drawable d) {
touch.setMaxZoom(4f);
touch.setImageDrawable(d);
setContentView(touch);
}
}
public void createUrlImage(String url){
new CreateImage().execute(url);
}
and in the onCreate() i put createUrlImage(url). I modified TouchImageView by adding :
在 onCreate() 中,我放置了 createUrlImage(url)。我通过添加以下内容修改了 TouchImageView:
public void setImageDrawable(Drawable dr) {
super.setImageDrawable(dr);
bmWidth = dr.getIntrinsicWidth();
bmHeight = dr.getIntrinsicHeight();
}
回答by Mike Ortiz
EDIT: Double Tap Zoom, Fling and other features have been added to TouchImageView since I originally answered this question. You can check it out on github here.
编辑:自从我最初回答这个问题以来,TouchImageView 中添加了双击缩放、Fling 和其他功能。您可以在此处在 github 上查看。
I added some usage details to the original post here. The code already has pinch zoom and panning, along with boundaries. Also, zooming out will return you to the original sized image.
我在这里的原始帖子中添加了一些使用细节。该代码已经具有捏合缩放和平移以及边界。此外,缩小将使您返回到原始大小的图像。
Adding double tap zoom will take more work. You'll have to use a GestureDetector and override onDoubleTap and onSingleTapConfirmed. You'll then want to make sure you pass your touch events to gestureDetector, without interfering with the rest of the code (see how events are passed to mScaleDetector at the beginning of onTouch). You'll want to get rid of the call to performClick() in ACTION_UP and instead place it in onSingleTapConfirmed. You can check this answerfor some skeletal code to get you started in implementing GestureDetector.
添加双击缩放需要更多的工作。您必须使用 GestureDetector 并覆盖 onDoubleTap 和 onSingleTapConfirmed。然后,您需要确保将触摸事件传递给gestureDetector,而不会干扰其余代码(查看onTouch 开始时如何将事件传递给mScaleDetector)。您将希望摆脱 ACTION_UP 中对 performClick() 的调用,而是将其放在 onSingleTapConfirmed 中。您可以查看此答案以获得一些骨架代码,以帮助您开始实施 GestureDetector。
Let me know if you manage to get double tap zoom solid and I'll add your changes to the original post and the Github repo.
如果您设法获得双击缩放,请告诉我,我会将您的更改添加到原始帖子和 Github 存储库中。