【问题标题】:How does TouchImageView works?TouchImageView 是如何工作的?
【发布时间】:2011-11-21 10:25:55
【问题描述】:

我的 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);
}

}

要使用的是我创建了一个私有类:

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();
}

【问题讨论】:

    标签: java android image


    【解决方案1】:

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


    我在原帖here 中添加了一些使用细节。该代码已经具有缩放和平移以及边界。此外,缩小会使您返回到原始大小的图像。

    添加双击缩放需要更多的工作。您必须使用 GestureDetector 并覆盖 onDoubleTap 和 onSingleTapConfirmed。然后,您需要确保将触摸事件传递给gestureDetector,而不会干扰其余代码(请参阅onTouch 开始时如何将事件传递给mScaleDetector)。您将希望摆脱 ACTION_UP 中对 performClick() 的调用,而是将其放在 onSingleTapConfirmed 中。您可以查看this answer 获取一些框架代码,以帮助您开始实施 GestureDetector。

    如果您设法使双击缩放稳定,请告诉我,我会将您的更改添加到原始帖子和 Github 存储库中。

    【讨论】:

    • 但是我不能把 TouchImageView 放在 Xml 布局中?
    • 我要传递的图像是我从 Asynctask 获得的可绘制对象。
    • 我对其进行了一些修改以放置一个可绘制对象而不是位图并且它正在工作,但我无法通过异步任务传递可绘制对象。
    • 您可以使用BitmapFactory.decodeResource(getResources(), R.drawable.icon) 将您的drawable 转换为位图。您可以在 XML 中使用 TouchImageView,但由于它是自定义视图,因此您必须输入全名:&lt;com.example.touch.TouchImageView android:id... /&gt;
    • @Hardik 实际上我刚刚回答了这个问题here。您将需要扩展 ViewPager 并向 TouchImageView 添加一个方法以使其工作。如果您有任何问题,请告诉我。
    猜你喜欢
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2016-11-13
    • 2017-10-11
    • 2021-10-13
    相关资源
    最近更新 更多