Android开发过程中,针对View视图坐标系必要时获取坐标,其重要性不言而喻。坐标系分为屏幕坐标系和View视图坐标系,前者用于真实坐标,后者用于获取相对坐标和宽高。
Android视图坐标系
android中的坐标系有两种:一种是Android坐标系,是相对屏幕原点来说的,也可以叫绝对坐标;另外一种是视图坐标系,是根据当前view以及父布局来说的。
Android坐标系
以屏幕左上角原点为中心,x轴向右为正,y轴向下为正。
视图坐标系
根据view自身相关属性计算view所处坐标。
获取View的距离和位置
下面介绍Android View类中用来获取View的距离和位置信息的一些API,这些API大都需要在Attach到Window之后才能获取到预期的结果。所以不能放在构造方法,onCreate(),onMeasure(),onLayout()等方法中执行,一般都需要放到onWindowFocusChanged()里,或者放到某个异步事件中执行。
getWidth()/getHeight()
getHeight():获取View自身高度;getWidth():获取View自身宽度。
getTranslationX()/getTranslationY()/getTranslationZ()
TranslationX和TranslationY是从Android3.0引入的View的属性,TranslationZ则是Android5.0引入的View的属性。它们分别表示将View从其原始位置沿着X,Y,Z轴方向平移的距离。
getTop()/getBottom()/getLeft()/getRight()/getElevation()
通过如下方法可以获得View到其父控件(ViewGroup)的距离:
- getTop():获取View自身顶边到其父布局顶边的距离
- getLeft():获取View自身左边到其父布局左边的距离
- getRight():获取View自身右边到其父布局左边的距离
- getBottom():获取View自身底边到其父布局顶边的距离
- getElevation():获取View Z轴偏移量
getElevation()的结果则是之前在XML中通过android:elevation配置的值,或者是通过setElevation()设置的值。其中getElevation()只有在Android5.0及之后的系统中才可以使用。
getX()/getY()/getZ()
getX()/getY()/getZ()同样是用来获取一个view到parent view的距离,和getTop()/getLeft()/getElevation()不同是,getX()/getY()/getZ()会考虑TranslationX,TranslationY和TranslationZ的影响。可以简单的将getTop()/getLeft()/getElevation()结果和getTranslationX()/getTranslationY()/getTranslationZ()结果相加,即可得到getX()/getY()/getZ()的结果。getX()和getY()只有在Android3.0及之后的系统才可以使用,getZ()只有在Android5.0及之后的系统中才可以使用。
getScrollX()/getScrollY()
getScrollX()/getScrollY()用来获取一个view滑动的距离,一般来说,如果View是不可滑动的,例如TextView,Button等, getScrollX()/getScrollY()获取到的始终是0。如果View是可以纵向滑动的,例如ListView,ScrollView等,getScrollX()获取到的始终是0,getScrollY()获取到的是Y轴滚动的距离。如果View是可以横向滑动的,例如HorizontalScrollView,getScrollY()获取到的始终是0,getScrollX()获取到的是X轴滚动的距离。getScrollX()和getScrollY()的值始终大于等于0。
getDrawingRect()
getDrawingRect()用来获取一个View的绘制区域,它本身没有返回值,需要传入一个不为null的Rect对象作为输出参数。一般来说,一个View的绘制区域就是从(0, 0)到(width, height)的区域,但如果View是可滑动的,则它的绘制区域还要加上滑动的距离,也就是从(scrollX, scrollY)到(width+scrollX, height+scrollY)的距离。
需要注意的是getDrawingRect()并没有考虑setScaleX(),setScaleY()和setRotation()的影响,所以它返回的区域大小并不一定会和View当前实际显示的区域大小相同。
getLocationOnScreen()和getLocationInWindow()
getLocationOnScreen()和getLocationInWindow()返回的都是view左上角的坐标,不同的getLocationOnScreen()得到的是相对于屏幕的坐标,也就是坐标原点在屏幕的左上角。而getLocationInWindow()得到的是相对于当前窗口的坐标,也就是坐标原点在窗口的左上角。
int[] screenLocation = new int [2];
int[] windowLocation = new int [2];
getLocationInWindow();
getLocationOnScreen(windowLocation)
getGlobalVisibleRect()和getLocalVisibleRect()
这两个方法主要用于判断一个 View 是在某个区域的可见性,区别:
- View.getGlobalVisibleRect(rect); //以屏幕 左上角 为参考系的
- View.getLocalVisibleRect(rect); //以目标 View 左上角 为参考系
判断是否可见:
boolean localVisibleRect = target.getLocalVisibleRect(rect);
返回值:
- true : View 全部或者部分 可见
- false : View 全部不可见
点击事件MotionEvent提供的坐标方法
我们看视图坐标系图示中那个深蓝色的点,假设就是我们触摸的点,我们知道无论是View还是ViewGroup,最终的点击事件都会由onTouchEvent(MotionEventevent)方法来处理,MotionEvent也提供了各种获取焦点坐标的方法:
- getX():获取点击事件距离控件左边的距离,即视图坐标
- getY():获取点击事件距离控件顶边的距离,即视图坐标
- getRawX():获取点击事件距离整个屏幕左边距离,即绝对坐标
- getRawY():获取点击事件距离整个屏幕顶边的的距离,即绝对坐标
几个问题
- View 的 getY(), getTranslationY() 和 getTop() 之间的联系;
- View 的 scrollTo() 和 scrollBy();
View的getY(),getTranslationY()和getTop()之间的联系:
getY() = getTranslationY()+ getTop();
scrollTo()和scrollBy()从字面意思我们可以知道scrollTo()是滑动到哪里的意思 ,scrollBy()是相对当前的位置滑动了多少。
需注意:scrollTo和scrollBy函数的参数和坐标系是“相反的”,比如 scrollTo(-100,0),View 的内容是向X轴正方向移动的。
view坐标获取时机
一般来说,我们要获取View的坐标和高度等,都必须等到View绘制完毕以后才能获取的到,在Activity的onCreate()方法里面是获取不到的,必须等到View绘制完毕以后才能获取地到View的响应的坐标,一般来说,主要有以下两种方法。
第一种方法,onWindowFocusChanged()方法里面进行调用
因为onWindowFocusChanged可能会调用多次,所以我们可以用一个唯一标识来控制获取坐标调用一次即可。
第二种方法,在视图树绘制完成的时候进行测量
利用view.getViewTreeObserver().addOnGlobalLayoutListener监听view是否整个绘制完毕,然后进行获取坐标。
最后
我是i猩人,转载注明出处,喜欢本篇文章的童鞋欢迎点赞、关注哦。
参考
- https://blog.csdn.net/itachi85/article/details/50708391
- https://juejin.im/entry/5880209c2f301e006968a342