~~谢谢~~

  图为放大前和放大并拖动后

android 计算控件距离 android 控件坐标_坐标轴

android 计算控件距离 android 控件坐标_逻辑坐标_02

控件功能

1.       支持坐标轴单位长度的放大缩小

2.       放大缩小基于坐标轴中间位置缩放,即中间位置的那个点为参考点,在程序中需要记录它的物理坐标和逻辑坐标,并且逻辑坐标随着拖动和缩放而不断变化,其他所有坐标的物理逻辑坐标之间的转换都是以此作为参考点的,这样可以使得缩放的时候让人感觉在用google地图(夸张了点)。

3.       支持内容拖动

4.       支持坐标轴名称和单位设置

5.       支持标题设置

6.       支持边距和标题高度设置

7.       支持添加任意多条不同折线,且可以由用户决定用什么样的Paint。

实现缩放和移动的关键为参考点的变化和坐标转换。

1.       坐标轴密度K


/*

     * 横轴纵轴密度、长度和比例。

*/

private float mXValuePerPix, mYValuePerPix;

private float mXScale, mYScale;

    mXValuePerPix / mXScale 为X轴的密度

    mYValuePerPix / mYScale 为Y轴的密度


2.       移动的时候参考点的变化


/*

     * 用于保存拖动时的上一个点的位置

*/

int x0, y0;



/*

     * 拖动事件监听

*/

    @Override

public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

/*

        * (x,y)点为发生事件时的点,它的坐标值为相对于该控件左上角的距离

*/

int x = (int) event.getX();

int y = (int) event.getY();

switch (action) {



case MotionEvent.ACTION_DOWN: // 按下

           x0 = x;

           y0 = y;

           Log.i("down", "(" + x0 + "," + y0 + ")");

break;

case MotionEvent.ACTION_MOVE: // 拖动

/*

            * (x-x0, y-y0)为物理坐标相对运动矢量

            * mXValuePerPix / mXScale 为X轴的密度

            * mYValuePerPix / mYScale 为Y轴的密度

            * 即每个像素长度代表的长度

            *

            * 向右和向上移动的时候,坐标值都是变大的,而参考点是不动的所以相对来说是变小的

            * 但是物理Y轴的矢量应该先取反,因为物理坐标点的坐标轴是向下Y增大的。

*/

           mPointBaseValue.x -= (x - x0) * mXValuePerPix / mXScale;

           mPointBaseValue.y -= -(y - y0) * mYValuePerPix / mYScale;

           x0 = x;

           y0 = y;

           Log.i("move", "(" + x0 + "," + y0 + ")");

           invalidate();

break;

case MotionEvent.ACTION_UP: // 弹起

break;

       }

/*

        * 注意:这里一定要返回true 返回false和super.onTouchEvent(event)都会本监听只能检测到按下消息

        * 这是因为false和super.onTouchEvent(event)的处理都是告诉系统该控件不能处理这样的消息,

        * 最终系统会将这些事件交给它的父容器处理。

*/

return true;

    }


3.       坐标转换


/**

     * 逻辑坐标转化为屏幕坐标

     * 将逻辑坐标logPointF点转换为物理坐标

*/

private PointF point2Physical(PointF logPointF) {

       PointF physicalPointF = new PointF();

       physicalPointF.set((logPointF.x - mPointBaseValue.x) * mXScale

              / mXValuePerPix + mPointBase.x,

              -(logPointF.y - mPointBaseValue.y) * mYScale / mYValuePerPix

                     + mPointBase.y);

return physicalPointF;

    }



/**

     * 物理坐标转化为逻辑坐标

     * 将物理坐标phyPointF点转换为逻辑坐标

*/

private PointF point2Logical(PointF phyPointF) {

float x = (phyPointF.x - mPointBase.x) * mXValuePerPix / mXScale

              + mPointBaseValue.x;

float y = (mPointBase.y - phyPointF.y) * mYValuePerPix / mYScale

              + mPointBaseValue.y;

       PointF logicalPointF = new PointF(x, y);

return logicalPointF;

    }


 4.       程序中所用的成员变量一览


/*

     * 颜料

*/

private Paint mPaint;

/*

     * 数据集合

*/

private List<PointF[]> mPointsList;

private List<Paint> mPaintList;

/*

     * 标题

*/

private boolean mHasTitle;

private String mTitle;

private int mTitleHeight;

private PointF mTitlePoint;

/*

     * 边距

*/

private int mLeftPad, mRightPad, mBottomPad, mTopPad;

/*

     * 横轴纵轴密度、长度和比例。

*/

private float mXValuePerPix, mYValuePerPix;

private int mXLen, mYLen;

private float mXScale, mYScale;

/*

     * 横轴纵轴标识和单位

*/

private String mXAxisPrickle, mYAxisPrickle;

private String mXAxisName = "X", mYAxisName = "Y";

/*

     * 圆心(坐标值是相对与控件的左上角的)

*/

// private PointF mPointZero = new PointF();

/*

     * 参考坐标

*/

private PointF mPointBase = new PointF();

private PointF mPointBaseValue = new PointF();

/*

     * 交叉点坐标中心点

*/

private PointF mPointOrigin = new PointF();


源码下载:CoordinatesTest.zip