View坐标的那些琐碎知识点你知道吗

Android开发过程中,针对View视图坐标系必要时获取坐标,其重要性不言而喻。坐标系分为屏幕坐标系和View视图坐标系,前者用于真实坐标,后者用于获取相对坐标和宽高。

Android视图坐标系

android中的坐标系有两种:一种是Android坐标系,是相对屏幕原点来说的,也可以叫绝对坐标;另外一种是视图坐标系,是根据当前view以及父布局来说的。

Android坐标系

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是否整个绘制完毕,然后进行获取坐标。

参考

  • https://blog.csdn.net/itachi85/article/details/50708391
  • https://juejin.im/entry/5880209c2f301e006968a342

猜你喜欢

转载自blog.csdn.net/li0978/article/details/114374720
今日推荐