Android自定义View之View的位置参数

最近在学习自定义View,总是被View的显示的位置搞的一头雾水。对于一个View的位置,我比较迷惑:

  1. View在显示在哪个位置?
  2. View的宽和高的定义?

什么是View

View是Android中所有控件的基类,不管是Button或者TextView,还是LinearLayout或者ViewGroup,都继承于View。所以说,View是用户界面最基本的控件,用于创建交互式UI组件。

ViewGroup的字面意思是一组的View,其是View的子类,它是保存其他视图(或者其他ViewGroup),并定义其布局属性的容器。

在Android设计中,ViewGroup也继承了View,意味着View本身不仅是一个控件,其还是多个控件组成的一组控件。通过这些关系也就形成了我们所熟悉的View树形结构。

Android自定义View之View的位置参数_第1张图片

View的位置参数

在Android中,默认的View的形状都是矩形。也就是说,只要确定了View的左上顶点和右下顶点的坐标,我们就可以确定了View的位置。这两个顶点分别对应了View的四个属性:

  • top:左上角纵坐标
  • left:左上角横坐标
  • bottom:右下角纵坐标
  • right:右下角横坐标

值得注意的是,这里所说的坐标都是相对坐标,这些坐标都是相对于父容器来说的。在Android系统中,屏幕的左上角作为,整个坐标系的原点,x轴和y轴的正向分别为右和下,大部分的Android的系统都是按照这个坐标系来进行显示的。

Android自定义View之View的位置参数_第2张图片

上图中,涉及到了以下方法:

  • view获取自身宽高:getHeight(),getWidth()
  • view获取自身坐标:getLeft(),getTop(),getRight(),getBottom()
  • MotionEvent获取坐标:getX(),getY(),getRawX(),getRawY()

view获取自身坐标

View获取View的自身宽高不用多说,从方法命名上就可以看出来。

对于View本身是放置在一个ViewGroup中,先不管ViewGroup的大小,我们只要关心View在ViewGroup的位置就好了。前面我们已经提到了View在ViewGroup的位置是由View的4个位置属性决定的,它们之间的关系是这样的

  • getTop():获取到的是view自身的顶边到其父布局顶边的距离,即view的top属性
  • getLeft():获取到的是view自身的左边到其父布局左边的距离,即view的left属性
  • getRight():获取到的是view自身的右边到其父布局左边的距离,即view的right属性
  • getBottom():获取到的是view自身的底边到其父布局顶边的距离,即view的Bottom属性

从图中,我们可以清楚地得到View的宽高和View自身坐标之间的关系:

width = right - left
      = getRight() - getLeft()

heiht = bottom - top
      = getBottom() - getTop()

Android 3.0新添属性

在Android 3.0以后,对View又新添了4个属性:

x:view左上角的横坐标
y:view左上角的纵坐标
translationX:左上角相对于父容器的偏移量
translationY:左上角相对于父容器的偏移量

这几个参数坐标都是相对于父容器的相对坐标,并且translationX和translationY的默认值都是0,view也分别为它们提供了get()和set方法。它们之间的换算关系是:

x = lef + translationX;
y = top + translationY;

值得注意的是,View在平移的过程中,top和Left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x、y、translationX和translationX这四个参数。

Android自定义View之View的位置参数_第3张图片 Android自定义View之View的位置参数_第4张图片

Android 5.0新添属性

在Android 5.0,对View又添加了一个新属性z,此新属性表示视图的标高,其确定:

  • 阴影的大小:具有较高Z值的视图会投射更大的阴影。
  • 绘制顺序:具有较高Z值的视图显示在其他视图的顶部。

View的Z值有两个组成部分:

  • elevation:静态组件。

    定义elevation属性:

    1. XML中使用android:elevation属性
    2. 代码中设置视图的View.setElevation() 
    
  • translationZ:用于动画的动态组件。

    Z = elevation + translationZ

在Material设计中,Z属性占了很大比重,由Z属性表示的视图的高程确定其阴影的视觉外观:具有较高Z值的视图投射较大,较柔和的阴影。 具有较高Z值的视图会遮挡具有较低Z值的视图; 但是,视图的Z值不会影响视图的大小。

MotionEvent获取坐标

对于MotionEvent这四个方法,也是获取View的坐标,其所对应的的参考点不一样,它们的用途也不一样,具体该如何使用呢?在紧随其后的Android自定义View之MotionEvent会了解其使用情况。

  • getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离
  • getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离
  • getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离
  • getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离

动态获取View的位置

前面获取到的View的位置坐标都是相对坐标(相对于父容器),而在MotionEvent所提供的四个方法中,可以获取到是点击事件相对坐标。有时候需要获取View在整个屏幕的位置,这个时候,又该如何呢?在View中定义了这样的四个方法:

  • getLocationInWindow(int[])
  • getLocationOnScreen(int[])
  • getGlobalVisibleRect(Rect)
  • getLocalVisibleRect()

getLocationInWindow

int[] position = new int[2];  
textview.getLocationInWindow(position);  

这个方法是将view的左上角坐标存入数组中.此坐标是相对当前activity而言.

  1. 若是普通activity,则y坐标为可见的状态栏高度+可见的标题栏高度+view左上角到标题栏底部的距离.
  2. 若是对话框式的activity,则y坐标为可见的标题栏高度+view到标题栏底部的距离.

可见的意思是:在隐藏了状态栏/标题栏的情况下,它们的高度以0计算.

此时是无视状态栏的有无的.

getLocationOnScreen

int[] position = new int[2];  
textview.getLocationOnScreen(position);  

这个方法跟上面的差不多,也是将view的左上角坐标存入数组中.但此坐标是相对整个屏幕而言.

y坐标为view左上角到屏幕顶部的距离.

getGlobalVisibleRect

Rect viewRect = new Rect();  
textview.getGlobalVisibleRect(viewRect);  

这个方法是构建一个Rect用来”套”这个view.此Rect的坐标是相对当前activity而言.

  1. 若是普通activity,则Rect的top为可见的状态栏高度+可见的标题栏高度+Rect左上角到标题栏底部的距离.
  2. 若是对话框式的activity,则y坐标为Rect的top为可见的标题栏高度+Rect左上角到标题栏底部的距离.

此时是无视状态栏的有无的.

getLocalVisibleRect

Rect globeRect = new Rect();  
button.getLocalVisibleRect(globeRect);  

这个方法获得的Rect的top和left都是0,也就是说,仅仅能通过这个Rect得到View的宽度和高度.

以上方法在OnCreate方法中调用,都会返回0,这是因为View还未加载完毕.

建议在onWindowFocusChanged方法中进行获取,有些情况下onWindowFocusChanged不好用的时候(比如ActivityGroup),可以这样写:

mTextView.post(new Runnable() {  
    @Override  
    public void run() {  
        Rect viewRect = new Rect();  
        mTextView.getGlobalVisibleRect(viewRect);  
        mTreeScrollView.setRect(viewRect);  
    }  
});  

这样在View加载完毕之后会执行获取位置的方法.

参考资料

  1. android之View坐标系(view获取自身坐标的方法和点击事件中坐标的获取)
  2. android应用程序中获取view的位置
  3. Android tips(四)–>Android应用程序中获取view的位置

你可能感兴趣的:(android自定义view,Android进阶)