TouchImageView是如何工作的?

6

我有一个良好的TouchImageView,并且我想知道它在代码中是如何工作的: 我只想能够在任何我选择的Imageview上捏合缩放,或使用双击缩放,并且当我缩小时,我会返回到图像的原始大小。 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);
}

}

为了使用它,我创建了一个私有类:
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);
}

在onCreate()中,我添加了createUrlImage(url)。我通过添加以下内容修改了TouchImageView:

public void setImageDrawable(Drawable dr) { 
super.setImageDrawable(dr);
bmWidth = dr.getIntrinsicWidth();
bmHeight = dr.getIntrinsicHeight();
}
1个回答

7

编辑:自我最初回答这个问题以来,TouchImageView已经添加了双击缩放、快速滑动和其他功能。你可以在github上查看这里


我在原始帖子这里添加了一些使用细节。代码已经具备了捏合缩放和平移的功能,同时还有边界。此外,缩小图像将返回到原始大小。

添加双击缩放需要更多的工作。您需要使用GestureDetector并覆盖onDoubleTap和onSingleTapConfirmed。然后,您需要确保将触摸事件传递给gestureDetector,而不会干扰其余代码(请参见如何在onTouch的开头将事件传递给mScaleDetector)。您需要在ACTION_UP中删除对performClick()的调用,并将其放置在onSingleTapConfirmed中。您可以查看这个答案获取一些骨架代码,以帮助您开始实现GestureDetector。

如果您成功地实现了双击缩放,请告诉我,我将把您的更改添加到原始帖子和Github存储库中。


@Mike Ortiz,我在使用分页器时遇到了问题。当我缩放图像并向左或向右滑动时,它会显示分页器中的下一项而不是拖动图像。我希望当图像被缩放时,用户无法滑动分页器。我尝试了许多解决方案,但都没有帮助我实现这种行为。有没有什么方法可以做到这一点?顺便说一句,感谢您提供的库,这是迄今为止最好的库。 - SkyWalker
1
@Hardik 我刚刚在这里回答了这个问题(https://dev59.com/s2Ei5IYBdhLWcg3wyO04#20944068)。你需要扩展ViewPager并添加一个方法到TouchImageView中使其工作。如果你有任何问题,请告诉我。 - Mike Ortiz
嗨,Mike,我怎么去掉边框? - Amanni
@Amanni,不确定你的意思。也许你想将宽度和高度设置为“wrap_content”。或者,将scaleType设置为“CENTER_CROP”。 - Mike Ortiz
@MikeOrtiz,你是如何开发出这么好的库的?你是从哪里学到的呢? - TechChain
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接