坐标类别
一般来说,Android中存在三类坐标:
- 屏幕坐标:以屏幕的左上角为原点,水平向右为x轴正方向,竖直向下为y轴正方向。
- 布局坐标:以view的左上角为原点,水平向右为x轴正方向,竖直向下为y轴正方向。之所以称之为布局坐标是因为view的左上角的位置是在view的layout过程中确定的。
- 视图坐标(绘制坐标):视图坐标是view的draw过程中绘制内容时参考的坐标。存在于一个抽象的画布上。
在理解视图坐标上,很重要的一点是:draw过程中,我们的画布是无限大的,画布上有一个直角坐标系,称之为视图坐标。你可以以视图坐标为基准在画布上随便画点啥。View的layout过程中的四个参数(l,t,r,b)确定了一个矩形框。矩形框在屏幕上且在屏幕上的位置一般是不会改变的,矩形框的左上角就是当前View的布局坐标。我们拿一个和这个矩形框一样大小的另一个矩形框放到画布上,其左上角与视图坐标重合,画布上的矩形框在画布上框住的内容就会绘制到屏幕上对应的矩形框。当调用scrollto或scollby方法时,画布不动,画布上的矩形框移动。这个过程中,视图坐标在画布上的位置始终不变,布局坐标在屏幕上的位置始终不变。
打个比方:我们有一张小的白纸,对应于手机屏幕,白纸上画了一个矩形,对应于手机上View layout过程确定的矩形框,其左上角对应于当前View的布局坐标。我们在地上放了一张超大的白纸,对应于上面的说的画布,超大白纸上画了一个直角坐标系,相当于视图坐标。在超大白纸上方放了一个超大的纸板(不透明),纸板上有个矩形的洞,矩形的左上角与超大白纸的坐标对齐。这个洞就对应于上面所说的画布上的矩形框。当调用scrollto或者scrollby方法时,移动纸板。透过矩形框看见的内容,画到小的白纸上的矩形框中,相当于显示在了屏幕上。这个过程中,小的白纸上的布局坐标没有变,大的白纸上的视图坐标也没有变。
每个View都有自己的画布和画布上的视图坐标。画布独立于屏幕,和屏幕没有直接关系。子View上显示的内容会覆盖父View上显示的内容。
注:视图坐标和布局坐标的概念引用自Android内核剖析,除了这本书之外,博主还未见到其他地方有类似的定义。虽然这个坐标系的分类没有被广泛的传播,但是不可否认的是,这个坐标体系很好,很清晰。这应该是scrollTo和scrollBy为什么是“反的”的最好理论解释了。
下面这张图是我的gmail的截屏。
gmail.jpg其组成主要有,顶部的状态栏,toolbar,RecyclerView,底部的导航栏。可以看出其中的坐标系包括
- 屏幕坐标
- 布局坐标:顶部的状态栏,toolbar,RecyclerView,底部的导航栏的左上角组成的坐标。
- 视图坐标:默认和布局坐标相同。当RecycleView滑动时,画布上的矩形框移动,画布不动,导致显示的内容改变。
程序员可用区域
在Activity中,有一个phoneWindow对象,用于管理view树,view树的根是系统为我们设置的DecorView。DecorView会根据主题信息在View树中添加相应的节点(例如ActionBar)。我们可以通过setContentView设置一个view到view树中。这个view所在的区域就是程序员的可用区域。一般有两种情况:
- 有ActionBar
ActionBar由系统绘制,应用程序员可用的区域从ActionBar底部到底部导航栏顶部。 - 无ActionBar
如果设置了无ActionBar的主题,应用程序员可用的区域从状态栏底部到底部导航栏顶部。
View的尺寸和位置
View中有四个属性:
protected int mLeft;
protected int mRight;
protected int mTop;
protected int mBottom;
其值由layout过程的四个参数(l,t,r,b)确定。这四个参数的设置一般会参考measure过程中测量出来的值。View的四个属性值表示layout过程中确定的基本位置。含义如下图所示,坐标系是父View的视图坐标:
View位置信息.jpgView有四个方法:
getLeft();
getRight();
getTop();
getRight();
可以获得这四个参数。
下面这两个方法
offsetLeftAndRight(int offset);
offsetTopAndBottom(int offset);
可以改变mLeft,mRight,mTop,mBottom的值
Android3.0以后,View又增添了一些关于位置的属性。
x,y
translationX
translationY
TransitionX和TranslationY表示View位置的偏移量,初始值为0,
x,y表示view左上角的坐标,坐标系是其父View的视图坐标。其值为
x = mleft + tranlationX
y = mtop + tranlationY
下面两个方法
setTranslationX();
setTranslationY();
会改变TransitionX,TranslationY的大小,x,y的大小也随之改变,但是不会改变mTop,mLeft,mRight,mBottom的值。View的位置也会改变。view的布局坐标也会改变。
View中还有几个关于view大小的方法
getWidth() //返回 mRight - mLeft
getHeight() //返回 mBottom - mTop
getMeasureWidth() // 返回measure过程测量出来的View的大小
getMeasureHeight() // 返回measure过程测量出来的View的大小
点击事件的位置
点击事件使用MotionEvent表示,其常用的方法有:
getX():触摸点在当前View的布局坐标系中的横坐标
getY():触摸点在当前View的布局坐标系中的纵坐标
getRawX():触摸点在屏幕坐标系中的横坐标
getRawY():触摸点在屏幕坐标系中的纵坐标