安卓中ImageView的拖动限制

7

我是一位有用的助手,可以为您翻译文本。

我在布局中有一个ImageView,并在ImageView上设置了OnTouchListener以拖动ImageView。它完美地工作。我的问题是如何防止移动ImageView超出布局范围?

这是我的代码:

Activity类:

public class RepositionTestActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.reposition_test_layout);
        ImageView imageView = (ImageView)findViewById(R.id.android);
        imageView.setOnTouchListener(new Touch());
    }
}

Touch类:

public class Touch implements OnTouchListener {

    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;

    private static final float MIN_ZOOM = 1f;
    private static final float MAX_ZOOM = 5f;

    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();

    private PointF start = new PointF();
    private PointF mid = new PointF();

    private int mode = NONE;
    private float oldDistance = 1f;

    public boolean onTouch(View view, MotionEvent event) {
        ImageView imageView = (ImageView)view;

        switch(event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                start.set(event.getX(), event.getY());
                mode = DRAG;
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                oldDistance = spacing(event);
                if(oldDistance > 10f) {
                    savedMatrix.set(matrix);
                    midPoint(mid, event);
                    mode = ZOOM;
                }
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                break;

            case MotionEvent.ACTION_MOVE:
                if(mode == DRAG) {
                    matrix.set(savedMatrix);
                    matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
                }
                else if(mode == ZOOM) {
                    float newDistance = spacing(event);
                    if(newDistance > 10f) {
                        matrix.set(savedMatrix);
                        float scale = newDistance / oldDistance;
                        float[] values = new float[9];
                        matrix.getValues(values);
                        float currentScale = values[Matrix.MSCALE_X];
                        if(scale * currentScale > MAX_ZOOM) 
                            scale = MAX_ZOOM / currentScale;
                        else if (scale * currentScale < MIN_ZOOM)
                            scale = MIN_ZOOM / currentScale;
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                }
                break;
        }
        imageView.setImageMatrix(matrix);
        return true;
    }

    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }

    private void midPoint(PointF point, MotionEvent event) {
        point.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2);
    }

}

布局XML:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/reposition_test_layout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/android"
        android:src="@drawable/android"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:scaleType="matrix"
        android:contentDescription="@string/android_description" >
    </ImageView>

</LinearLayout>

enter image description here


1
我编辑了它。你可以看到完整的类。 - Vahid Javaherifar
5个回答

12

将以下参数添加到Touch类中:

private float dx; // postTranslate X distance
private float dy; // postTranslate Y distance
private float[] matrixValues = new float[9];
float matrixX = 0; // X coordinate of matrix inside the ImageView
float matrixY = 0; // Y coordinate of matrix inside the ImageView
float width = 0; // width of drawable
float height = 0; // height of drawable

case MotionEvent.ACTION_MOVE:后修改您的代码。

if (mode == DRAG) {
        matrix.set(savedMatrix);

        matrix.getValues(matrixValues);
        matrixX = matrixValues[2];
        matrixY = matrixValues[5];
        width = matrixValues[0] * (((ImageView) view).getDrawable()
                                .getIntrinsicWidth());
        height = matrixValues[4] * (((ImageView) view).getDrawable()
                                .getIntrinsicHeight());

        dx = event.getX() - start.x;
        dy = event.getY() - start.y;

        //if image will go outside left bound
        if (matrixX + dx < 0){
            dx = -matrixX;
        }
        //if image will go outside right bound
        if(matrixX + dx + width > view.getWidth()){
            dx = view.getWidth() - matrixX - width;
        }
        //if image will go oustside top bound
        if (matrixY + dy < 0){
            dy = -matrixY;
        }
        //if image will go outside bottom bound
        if(matrixY + dy + height > view.getHeight()){
            dy = view.getHeight() - matrixY - height;
        }
        matrix.postTranslate(dx, dy);   
    }

非常感谢您提供这段代码。 您是否有适用于iPhone的相同代码? - Anshul
1
你好,感谢您的支持。我想在缩放图像时也想绑定图像,请提供解决方案。 - Anshul
嗨@Anshul。最好在SO上提出另一个问题,这样其他人就可以看到并帮助你了。 - Benito Bertoli
嗨,我需要帮助。我已经完成了,但有时会出现问题。请帮忙看一下,我发了我的代码。 - Anshul
请问矩阵的用途和使用方法是什么? - Maulik Santoki
显示剩余4条评论

1
我使用了Benito Bertoli的答案,并修改了ACTION_MOVE代码,改变了小和大符号,以便对放大的图像进行缩放和拖动

这是代码

private static final float MIN_ZOOM = 1f; 
private static final float MAX_ZOOM = 2.5f; 

public boolean onTouch(View v, MotionEvent event) {
    ImageView view = (ImageView) v;
    view.setScaleType(ImageView.ScaleType.MATRIX);

    // Handle touch events here...
    switch (event.getAction() & MotionEvent.ACTION_MASK) {

        case MotionEvent.ACTION_DOWN: //first finger down only
            savedMatrix.set(matrix);
            start.set(event.getX(), event.getY());
            Log.d(TAG, "mode=DRAG" );
            mode = DRAG;
            break;
        case MotionEvent.ACTION_UP: //first finger lifted
        case MotionEvent.ACTION_POINTER_UP: //second finger lifted
            mode = NONE;
            Log.d(TAG, "mode=NONE" );
            break;
        case MotionEvent.ACTION_POINTER_DOWN: //second finger down
            oldDist = spacing(event);
            Log.d(TAG, "oldDist=" + oldDist);
            if (oldDist > 10f) {
                savedMatrix.set(matrix);
                midPoint(mid, event);
                mode = ZOOM;
                Log.d(TAG, "mode=ZOOM" );
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (mode == DRAG) {
                //matrix.set(savedMatrix);
                //matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
                matrix.set(savedMatrix);

                matrix.getValues(matrixValues);
                matrixX = matrixValues[2];
                matrixY = matrixValues[5];
                width = matrixValues[0] * (view.getDrawable().getIntrinsicWidth());
                height = matrixValues[4] * (view.getDrawable().getIntrinsicHeight());


                dx = event.getX() - start.x;
                dy = event.getY() - start.y;

                //if image will go outside left bound
                if (matrixX + dx  > 0){
                    Log.e("dx","lef bound " + dx);
                    dx = -matrixX;
                }
                //if image will go outside right bound
                if(matrixX + dx + width < view.getWidth()){
                    dx = view.getWidth() - matrixX - width;
                }
                //if image will go oustside top bound
                if (matrixY + dy > 0){
                    dy = -matrixY;
                }
                //if image will go outside bottom bound
                if(matrixY + dy + height < view.getHeight()){
                    dy = view.getHeight() - matrixY - height;
                }

                matrix.postTranslate(dx, dy);
            }
            else if (mode == ZOOM) {
                Float newDist = spacing(event);
                Log.d(TAG, "newDist=" + newDist);
                if (newDist > 10f) {
                    matrix.set(savedMatrix);
                    float scale = newDist / oldDist;
                    float[] values = new float[9];
                    matrix.getValues(values);
                    float currentScale = values[Matrix.MSCALE_X];
                    if(scale * currentScale > MAX_ZOOM)
                        scale = MAX_ZOOM / currentScale;
                    else if (scale * currentScale < MIN_ZOOM)
                        scale = MIN_ZOOM / currentScale;
                    matrix.postScale(scale, scale, mid.x, mid.y);

                }
                break;
            }
    } //perform the transformation.

    view.setImageMatrix(matrix);
    return true; // indicate event was handled

}

private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float)Math.sqrt(x * x + y * y);
}

private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}

    return drawable;
}

1

Android文档表示:

可以通过调用方法getLeft()getTop()来检索视图的位置。前者返回表示视图的矩形的左侧或X坐标。后者返回表示视图的矩形的顶部或Y坐标。这些方法都返回相对于其父级的视图位置。
此外,提供了几个方便的方法以避免不必要的计算,即getRight()getBottom()。这些方法返回表示视图的矩形的右侧和底部边缘的坐标。例如,调用getRight()类似于以下计算:getLeft() + getWidth()。

因此,在移动图像之前,您可以获取其坐标,并且可以在OnTouchListener类中计算移动量。现在,如果(您的图像的X坐标加上您计算的水平移动大于设备宽度您的图像的Y坐标加上您计算的垂直移动大于设备高度),则您的图像将不会移动。


尽管这些信息是正确的,但翻译忽略了左和上属性。因此,您可以具有a!= 0的xy平移,仍然将getTop()和getLeft()作为= 0。 - Renato Probst

1
  1. We need to create two Rect objects, one is for our view and another for our image according to the view coordinates.

    float[] values = new float[9];
    matrix.getValues(values);
    float globalX = values[Matrix.MTRANS_X];
    float globalY = values[Matrix.MTRANS_Y];
    float scaleX = values[Matrix.MSCALE_X];
    float scaleY = values[Matrix.MSCALE_Y];
    Rect viewRect = new Rect(0, 0, viewWidth, viewHeight);
    Rect imageRect = new Rect((int) globalX, (int) globalY, Math.round(bitmapWidth * scaleX + globalX),
            Math.round(bitmapHeight * scaleY + globalY));
    
    1. If we want our image be always inside our view, then we check this:

      if (!viewRect.contains(imageRect)) {
          matrix.set(lastSetMatrix); //return to last saved parameters
      }
      
    2. Sometimes we need our image always be bigger than our view to position a part of the image inside the view, then we can check this:

      if (!imageRect.contains(viewRect)) {
         matrix.set(lastSetMatrix);
      }
      

0

我已经完成了这段代码。当我缩放时,它不应该超出边界。它工作得很好。但是当它触及x=0和y=0的坐标时,它不会最小化。

int FLAG=0;   



 else if (mode == ZOOM) {

                    float newDistance = spacing(event);

                    Log.i("new distance ", newDistance+"");

                    matrix.getValues(matrixValues);
                    matrixX = matrixValues[2];
                    matrixY = matrixValues[5];
                    width = matrixValues[0]
                            * (((ImageView) view).getDrawable().getIntrinsicWidth());
                    height = matrixValues[4]
                            * (((ImageView) view).getDrawable()
                                    .getIntrinsicHeight());

                    dx = event.getX() - start.x;
                    dy = event.getY() - start.y;

                    // if image will go outside left bound
                    if (matrixX + dx < 0) {
                        FLAG=1;
                    }
                    if (matrixX + dx + width > view.getWidth()) {
                        FLAG=1;
                        //dx = view.getWidth() - matrixX - width;
                    }
                    // if image will go oustside top bound
                    if (matrixY + dy < 0) {
                        FLAG=1;
                        //dy = -matrixY;
                    }
                    // if image will go outside bottom bound
                    if (matrixY + dy + height > view.getHeight()) {
                        FLAG=1;
                        //dy = view.getHeight() - matrixY - height;
                    }
                if (matrixX + dx ==0 || matrixY + dy==0){ 
                    FLAG=0;
                }

                    if (newDistance > 10f && FLAG==0) {

                        matrix.set(savedMatrix);

                        float scale = newDistance / oldDistance;

                        float[] values = new float[9];

                        matrix.getValues(values);
                        float currentScale = values[Matrix.MSCALE_X];
                        if (scale * currentScale > MAX_ZOOM)
                            scale = MAX_ZOOM / currentScale;
                        else if (scale * currentScale < MIN_ZOOM)
                            scale = MIN_ZOOM / currentScale;
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                }
                break;

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