【问题标题】:Android getWidth, getHeight, getLeft, getRight not correct after setScaleX() , setScaleY()Android getWidth、getHeight、getLeft、getRight 在 setScaleX() 、 setScaleY() 之后不正确
【发布时间】:2013-02-13 06:40:31
【问题描述】:

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

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

我在 fakeview 中实现了触摸监听器,它应该在所有视图的前面。触摸事件会根据代码改变主视图

想问一下,缩放后能不能得到实际的left、top、width和height?left和top总是返回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());
        }
    }
}

【问题讨论】:

  • 把“event”改成“v”,比如把event.getX改成v.getX。
  • 谢谢!我刚得到 0,0 而得到 v 的 X,Y。代码 "Log.e(TAG, event.getX() + "," + event.getY()); " 改为 Log.e(TAG,"ACTION_MOVE:"+ v.getX() + "," + v.getY());
  • 是的,这是因为您的视图正在填充父视图(从 xml 中看起来)。 GetX 表示视图左侧的像素。 GetY 表示从顶部开始的像素。如果它填满了父母,那么它的边缘肯定会接触到左上角。

标签: android view drag-and-drop zooming


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    这就是我在我的情况下解决它的方法(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;
    }
    

    然而事实证明,android 3.1(也可能是 3.0)在处理 getLocationOnScreen 方法时没有考虑比例因子。 在像这样的 android 3.1 api 的情况下,我将在从我的 getViewRect(View) 函数返回它之前手动缩放矩形:

    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 的第一个分支),以便第二个只是一种解决方法:)

    【讨论】:

      猜你喜欢
      • 2015-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-30
      相关资源
      最近更新 更多