7

我在布局中有一个 ImageView 并在 ImageView 上设置 OnTouchListener 以拖动 ImageView。它运行良好。我的问题是如何防止将 ImageView 移出布局范围?

这是我的代码:

活动类:

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

触摸类:

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>

在此处输入图像描述

4

5 回答 5

13

将以下参数添加到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);   
    }
于 2012-08-19T20:53:11.510 回答
1

安卓文档说:

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

因此,您可以在移动图像之前获取图像坐标,并且可以在OnTouchListener类中计算移动量度。现在,如果(X coordinate of your image plus horizontal movement that you computed,be greater than device widthY coordinate of your image plus vertical movement that you computed,be greater than device height)图像不移动。

于 2012-08-19T19:54:49.417 回答
1
  1. 我们需要根据视图坐标创建两个 Rect 对象,一个用于我们的视图,另一个用于我们的图像。

    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 (!viewRect.contains(imageRect)) {
          matrix.set(lastSetMatrix); //return to last saved parameters
      }
      
    2. 有时我们需要我们的图像总是比我们的视图大以将图像的一部分定位在视图内,然后我们可以检查一下:

      if (!imageRect.contains(viewRect)) {
         matrix.set(lastSetMatrix);
      }
      
于 2016-09-08T00:38:53.187 回答
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;
}
于 2016-02-11T18:35:14.210 回答
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;
于 2013-10-25T07:16:30.227 回答