setScaleX(),setScaleY()之后的Android getWidth,getHeight,getLeft,getRight不正确

时间:2013-02-13 06:40:31

标签: android view drag-and-drop zoom

我尝试通过展开/捏合手势和相对布局上的拖放功能实现放大/缩小。

这是我的OnPinchListener处理缩放效果的代码。 mainView 是布局xml文件中定义的RelativeLayout。

我在 fakeview 中实现了触控侦听器,它应位于所有视图的前面。触摸事件将根据代码更改主视图

我想询问是否可以获得比例后的实际左,上,宽度和高度?它始终返回0,0表示左侧和上方,以及原始宽度和高度放大后。

非常感谢!

     <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear_layout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/zoomable_relative_layout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        >
          <ImageView
            android:id="@+id/imageView1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:src="@drawable/background" />
        </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relative_layout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:orientation="vertical" >



    </RelativeLayout>

</RelativeLayout>




public class MainActivity extends Activity {
    //ZoomableRelativeLayout mainView = null;
    RelativeLayout mainView = null;
    RelativeLayout rl = null;
    public static final String TAG = "ZoomText."
            + MainActivity.class.getSimpleName();
    private int offset_x;
    private int offset_y;
    private boolean dragMutex = false;
    RelativeLayout fakeView = null;
    float width = 0, height = 0;
    private OnTouchListener listener = new OnTouchListener() {

        @Override
        public boolean onTouch(View arg0, MotionEvent event) {
            // Log.e(TAG, event + "");
            // Log.e(TAG, "Pointer Count = "+event.getPointerCount());
            Log.e(TAG,
                    event.getX() + "," + event.getY() + "|" + mainView.getX()
                            + "(" + mainView.getWidth() + "),"
                            + mainView.getY() + "(" + mainView.getHeight()
                            + ")");
            if (event.getX() >= mainView.getLeft()
                    && event.getX() <= mainView.getLeft() + mainView.getWidth()
                    && event.getY() >= mainView.getTop()
                    && event.getY() <=mainView.getTop() + mainView.getHeight())
                if (event.getPointerCount() > 1) {
                    return scaleGestureDetector.onTouchEvent(event);
                } else {
                    return llListener.onTouch(arg0, event);
                }
            return false;

        }

    };

    private ScaleGestureDetector scaleGestureDetector;
    private OnTouchListener llListener = new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            // Log.d(TAG, event + ",LL");
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                offset_x = (int) event.getX();
                offset_y = (int) event.getY();
                // Log.e(TAG, offset_x + "," + offset_y);

                dragMutex = true;
                return true;
            case MotionEvent.ACTION_MOVE:
//              Log.e(TAG, "Finger down");
                int x = (int) event.getX() - offset_x;
                int y = (int) event.getY() - offset_y;
                Log.e(TAG, event.getX() + "," + event.getY());
                float _x = mainView.getX();
                float _y = mainView.getY();
                mainView.setX(_x + x);
                mainView.setY(_y + y);
                offset_x = (int) event.getX();
                offset_y = (int) event.getY();
                return true;
            case MotionEvent.ACTION_UP:
                dragMutex = false;
                return true;
            }
            return false;
        }

    };
    private OnDragListener dragListener = new View.OnDragListener() {

        @Override
        public boolean onDrag(View arg0, DragEvent arg1) {
            Log.e(TAG, "DRAG Listener = " + arg1);
            return false;
        }

    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainView = (RelativeLayout) findViewById(R.id.zoomable_relative_layout);
        // mainView.setOnTouchListener(new OnPinchListener());
        // mainView.setOnTouchListener(listener);
        scaleGestureDetector = new ScaleGestureDetector(this,
                new OnPinchListener());
        rl = (RelativeLayout) findViewById(R.id.linear_layout);
        mainView.setOnDragListener(dragListener);
        // mainView.setOnTouchListener(llListener);
        fakeView = (RelativeLayout) findViewById(R.id.relative_layout);
        fakeView.setOnTouchListener(listener);
    }

    class OnPinchListener extends SimpleOnScaleGestureListener {

        float startingSpan;
        float endSpan;
        float startFocusX;
        float startFocusY;

        public boolean onScaleBegin(ScaleGestureDetector detector) {
            startingSpan = detector.getCurrentSpan();
            startFocusX = detector.getFocusX();
            startFocusY = detector.getFocusY();
            return true;
        }

        public boolean onScale(ScaleGestureDetector detector) {
//          mainView.scale(detector.getCurrentSpan() / startingSpan,
//                  startFocusX, startFocusY);
//          if(width==0)
//              width = mainView.getWidth();
//          if(height==0)
//              height = mainView.getHeight();
            mainView.setPivotX(startFocusX);
            mainView.setPivotY(startFocusY);  
            mainView.setScaleX(detector.getCurrentSpan() / startingSpan);
            mainView.setScaleY(detector.getCurrentSpan() / startingSpan);  

//          LayoutParams  para = mainView.getLayoutParams();
//          width*=detector.getCurrentSpan() / startingSpan;
//          height*=detector.getCurrentSpan() / startingSpan;
//          para.width = (int)width;
//          para.height = (int)height;
//          mainView.setLayoutParams(para);


            return true;
        }

        public void onScaleEnd(ScaleGestureDetector detector) {
            //mainView.restore();
            mainView.invalidate();
            Log.e(TAG, mainView.getLeft()+","+mainView.getRight());
        }
    }
}

2 个答案:

答案 0 :(得分:1)

您需要获取转换矩阵并使用它来转换原始点。

这样的事情(在你进行缩放之后):

Matrix m = view.getMatrix(); //gives you the transform matrix
m.mapPoints(newPoints, oldPoints); //transform the original points.

答案 1 :(得分:0)

这就是我在我的情况下解决它的方法(getViewRect应该在视图布局后调用,例如通过view.post(Runnable),所以view.getWidth()/getHeight()返回实际值):

public static Rect getViewRect(View view) {
    Rect outRect = new Rect();
    outRect.right = (int)(view.getWidth() * getScalelX(view));
    outRect.bottom = (int)(view.getHeight() * getScalelY(view));
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    outRect.offset(location[0], location[1]);
    return outRect;
}


public static float getScalelX(View view) {
    float scaleX = view.getScaleX();
    view = getParent(view);
    while (view != null) {
        scaleX *= view.getScaleX();
        view = getParent(view);
    }
    return scaleX;
}

public static float getScalelY(View view) {
    float scaleX = view.getScaleY();
    view = getParent(view);
    while (view != null) {
        scaleX *= view.getScaleY();
        view = getParent(view);
    }
    return scaleX;
}

public static ViewGroup getParent(View view) {
    if (view == null) {
        return null;
    }
    ViewParent parent = view.getParent();
    if (parent instanceof View) {
        return (ViewGroup) parent;
    }
    return null;
}

然而事实证明,在处理getLocationOnScreen方法时,android 3.1(可能也是3.0)并没有考虑到帐户比例因子。 我想在我的getViewRect(View)函数返回之前手动缩放rect,以防android 3.1 api如下:

public static void scaleRect(Rect rect, float scaleX, float scaleY, float pivotX, float pivotY) {
    rect.left = (int) ((rect.left - pivotX) * scaleX + pivotX);
    rect.right = (int) ((rect.right - pivotX) * scaleX + pivotX);
    rect.top = (int) ((rect.top - pivotY) * scaleY + pivotY);
    rect.bottom = (int) ((rect.bottom - pivotY) * scaleY + pivotY);
}

但是,应该知道层次结构中从当前视图到根的每个视图的轴坐标以及相应的缩放级别,以正确处理此转换。

如果有人有任何直截了当的解决方案,我们将不胜感激

修改

这是我修改getViewRect(View)方法的方法,因此它也适用于3.1:

public static Rect getViewRect(View view) {
    Rect outRect = new Rect();
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR2){
        outRect.right = (int)(view.getWidth() * getScalelX(view));
        outRect.bottom = (int)(view.getHeight() * getScalelY(view));
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        outRect.offset(location[0], location[1]);
    } else {
        outRect.right = view.getWidth();
        outRect.bottom = view.getHeight();
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        outRect.offset(location[0], location[1]);
        View parent = view;
        while(parent != null){
            parent.getLocationOnScreen(location);
            scaleRect(outRect, parent.getScaleX(), parent.getScaleY(), parent.getPivotX() + location[0], parent.getPivotY() + location[1]);
            parent = getParent(parent);
        }
    }
    return outRect;
}

我认为可以删除if - 子句,以便第二个分支(else)适用于所有版本。但是我更喜欢使用简单的解决方案(if的第一个分支),以便第二个解决方案只是一种解决方法:)