【问题标题】:ImageView Drag Limitation In AndroidAndroid中的ImageView拖动限制
【发布时间】:2012-08-15 06:49:08
【问题描述】:

我在布局中有一个 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>

【问题讨论】:

  • 我编辑它。你可以看到完整的课程。

标签: java android touch-event ontouchlistener


【解决方案1】:

Android 文档说:

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

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

【讨论】:

  • 虽然此信息是正确的,但翻译忽略了 left 和 top 属性。所以你可以有一个 != 0 xy 翻译并且仍然得到 getTop() 和 getLeft() = 0。
【解决方案2】:

将以下参数添加到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。最好在 SO 上再问一个问题,以便其他人看到并帮助您。
  • 嗨,我需要它,但有时它会显示问题。请帮忙。我正在发布我的代码,请检查。
  • Benito Bertoli...你刚刚保存了整个 alpha 象限 :)
【解决方案3】:

我已经完成了这段代码。当我放大母鸡时,它不应该越界。它工作正常。但是当它触及 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;

【讨论】:

    【解决方案4】:

    我使用了 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;
    }
    

    【讨论】:

      【解决方案5】:
      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);
          }
          

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多