记Android里的坐标

Android的坐标系统其实是一个比较细也比较杂的东西,想一个小的对比文章,以后忘了可以看看。

首先是MotionEvent的getRawX和getX两个函数。这个还是比较简单的,getRawX取的是相对于屏幕的坐标,屏幕的原点(0,0)在左上角,X轴正方向是向右,Y轴正方向向下。getX是相对于父组件的坐标。

其次是几个View的函数(以Y轴为例)。

getY,getTranslationY,getScrollY,getTop,getHeight,还有一个就是getLocationInWindow。

首先说的是getY和getTranslationY,这两个函数有相同的地方,下面看跟踪进去看下View的getY的函数源码。

public void setY(float y) {
        setTranslationY(y - mTop);
    }

可以看到getY实际就是调用了getTranslationY,但是不同的是参数是y-mTop,mTop后面再说,看了源码大家应该有点了解了,其实两个函数是差不多的,只是有一个点小不同,不过这点小不同所带来的影响还是挺大的,大家在选用函数的时候要慎重,其实一般做View的移动,用getTranslationY比较多。

getScrollY是一个比较特别的函数,因为它涉及一个值叫mScrollY,简单说,getScrollY一般得到的都是0,除非你调用过scrollTo或scrollBy这两个函数。有几点要注意的是,不论是scrollTo或scrollBy,其实都是对View的内容进行滚动而不是对View本身,你可以做个小实验,一个LinearLayouy背景是黄色,里面放置一个子LinearLayout背景是蓝色,调用scrollTo或scrollBy,移动的永远是蓝色的子LinearLayout。还有就是scrollTo和scrollBy函数的参数和坐标系是“相反的”,比如scrollTo(-100,0),View的内容是向X轴正方向移动的,这个相反打引号是因为并不是真正的相反,具体可以看源码,关于这两个函数的源码分析大家可以看http://www.tuicool.com/articles/uM7ruy,一目了然。

关于getScrollY,我还想多说一句就是,scrollView的滚动,内部就是用scrollTo和scrollBy来进行的,所以可以用getScrollY来获取滚动的Y值,而listView并不是,listView源码的分析大家可以参考郭大侠最新的博客,分析的很透彻,所以使用getScrollY来获取listView滚动的Y值是行不通的,一直都是0,下面我提供一种计算listView滚动值的获取方法给大家参考一下。

public int getScrollY() {
        View c = mListView.getChildAt(0);
        if (c == null) {
            return 0;
        }
        int firstVisiblePosition = mListView.getFirstVisiblePosition();
        int top = c.getTop();
        int headerHeight = 0;
        if (firstVisiblePosition >= 1) {
            headerHeight = mPlaceHolderView.getHeight();
        }

        return -top + firstVisiblePosition * c.getHeight() + headerHeight;
    }

这里的mPlaceHolderView是listView的header,所以要单独考虑。这种方式适用于单一布局的listView。

getTop这个函数也比较特殊,(我讲起来比较虚因为我对它了解的还不是很深。。所以下面关于这个函数的看法,都只是我的一家之言,如果有大神了解的更多更好,希望您能指出我说的错误的地方,谢谢!) 它特殊就特殊在它“很难改变”,为什么这么说呢,因为你不管是调用setY,setTranslationY,scrollTo/scrollBy,getTop都不会改变,那getTop获取的是什么呢

public final int getTop() {
        return mTop;
    }

就是mTop,这个mTop之前也出现过,其实它代表的就是在View的layout过程中确定的top值,当你看setTop函数的源码,

public final void setTop(int top) {
        if (top != mTop) {
            final boolean matrixIsIdentity = hasIdentityMatrix();
            if (matrixIsIdentity) {
                if (mAttachInfo != null) {
                    int minTop;
                    int yLoc;
                    if (top < mTop) {
                        minTop = top;
                        yLoc = top - mTop;
                    } else {
                        minTop = mTop;
                        yLoc = 0;
                    }
                    invalidate(0, yLoc, mRight - mLeft, mBottom - minTop);
                }
            } else {
                // Double-invalidation is necessary to capture view's old and new areas
                invalidate(true);
            }

            int width = mRight - mLeft;
            int oldHeight = mBottom - mTop;

            mTop = top;
            mRenderNode.setTop(mTop);

            sizeChange(width, mBottom - mTop, width, oldHeight);

            if (!matrixIsIdentity) {
                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
                invalidate(true);
            }
            mBackgroundSizeChanged = true;
            invalidateParentIfNeeded();
            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                // View was rejected last time it was drawn by its parent; this may have changed
                invalidateParentIfNeeded();
            }
        }
    }
你会发现它会调用sizeChange这个函数,而不论是setY,setTranslationY还是scrollTo/scrollBy,都是不会调用的,所以我认为,这只是我认为啊,只有setTop/getTop这两个函数是关于一个View的“筋骨”的,也就是layout,其他几个函数都知识draw层面的,我也进行过验证,比如一个LinearLayout一开始getTop是250,height为500,使用其他函数,它的height是不会改变的,而当使用setTop(150)之后,这个LinearLayout的height就编程了600!这也算证实了我的猜测吧。

getHeight,没什么好说的,就是获取View的高度。

最后一个是getLocationInWindow,这个函数呢是这样用的,首先初始化一个数组:

private int[] location = new int[2];
然后

view.getLocationInWindow(childLocation);
之后location[0]就代表这个View相对于屏幕的X坐标,loacation[1]就代表这个View相对于屏幕的Y坐标了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值