View的基础知识
本文的内容大多数是摘抄自参考资料的,谨作本人的学习笔记使用,在此对参考资料的作者表示感谢。
什么是View
从类的角度来说,View就是Android中的一个类,而且是所有视图控件的基类。
从视图显示的角度来说,View就是一个显示控件,这个控件可以显示一些视图,同时可以对用户的点击,触摸等事件作出响应。View可以是一个控件,也可以是多个控件组成的一组控件,也就是ViewGroup,ViewGroup也继承自View,其内部可以包含View。
View的位置参数
在Android中,默认的View的形状都是矩形。也就是说,只要确定了View的左上顶点和右下顶点的坐标,我们就可以确定了View的位置。这两个顶点分别对应了View的四个属性:
- top: 左上角纵坐标
- left: 左上角横坐标
- bottom: 右下角纵坐标
- right: 右下角横坐标
值得注意的是,这里所说的坐标都是相对坐标,这些坐标都是相对于父容器来说的。在Android系统中,屏幕的左上角作为,整个坐标系的原点,x轴和y轴的正向分别为右和下,大部分的Android的系统都是按照这个坐标系来进行显示的。
上图中,涉及到了以下方法:
- 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自身坐标之间的关系:1
2
3width = 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方法。它们之间的换算关系是:
1 | x = lef + translationX; |
值得注意的是,View在平移的过程中,top和Left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x、y、translationX和translationX这四个参数。
验证代码:
1 | tv_test.setOnClickListener(new View.OnClickListener() { |
MotionEvent获取坐标
对于MotionEvent这四个方法,也是获取View的坐标,其所对应的的参考点不一样,它们的用途也不一样,具体该如何使用呢?在紧随其后的Android自定义View之MotionEvent会了解其使用情况。
- getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离
- getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离
- getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离
- getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离
动态获取View的位置
前面获取到的View的位置坐标都是相对坐标(相对于父容器),而在MotionEvent所提供的四个方法中,可以获取到是点击事件相对坐标。有时候需要获取View在整个屏幕的位置,这个时候,又该如何呢?在View中定义了这样的四个方法:
- getLocationInWindow(int[])
- getLocationOnScreen(int[])
getLocationInWindow
1 | int[] position = new int[2]; |
这个方法是将view的左上角坐标存入数组中.此坐标是相对当前activity而言.
- 若是普通activity,则y坐标为可见的状态栏高度+可见的标题栏高度+view左上角到标题栏底部的距离.
- 若是对话框式的activity,则y坐标为可见的标题栏高度+view到标题栏底部的距离.
可见的意思是:在隐藏了状态栏/标题栏的情况下,它们的高度以0计算.此时是无视状态栏的有无的.
Android中Activity界面:
getLocationOnScreen
1 | int[] position = new int[2]; |
这个方法跟上面的差不多,也是将view的左上角坐标存入数组中.但此坐标是相对整个屏幕而言.
y坐标为view左上角到屏幕顶部的距离.
关于区别如果还是不懂的话,建议阅读:android中getLocationInWindow 和 getLocationOnScreen的区别
需要注意的以上方法在OnCreate方法中调用,都会返回0,这是因为View还未加载完毕.建议在onWindowFocusChanged方法中进行获取,有些情况下onWindowFocusChanged不好用的时候(比如ActivityGroup),可以这样写:
1 | mTextView.post(new Runnable() { |
这样在View加载完毕之后会执行获取位置的方法.
MotionEvent和TouchSlop
MotionEvent
手机触摸屏幕产生的一系列事件中,典型的事件类型有如下三种:
- ACTION_DOWN 手指刚接触到屏幕
- ACTION_MOVE 手指在屏幕上移动
- ACTION_UP 手指从屏幕离开
手指触摸屏幕会产生一些列的点击事件,典型的是如下两种情况:
- 点击屏幕后离开松开,事件序列为DOWN->UP
- 点击屏幕滑动一会再松开,事件序列为DOWN->MOVE->…->MOVE->UP
如何获取点击位置的坐标,参考前面的纪录。
TouchSlop
TouchSloup是系统所能识别出的被认为是滑动的最小距离,这是一个常量,与设备有关,可通过以下方法获得:1
ViewConfiguration.get(getContext()).getScaledTouchSloup().
VelocityTracker、GestureDetector和Scroller
VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平放向速度和竖直方向速度。 使用方法:
1.在View的onTouchEvent方法中追踪当前单击事件的速度1
2VelocityRracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
2.计算速度,获得水平速度和竖直速度1
2
3velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int)velocityTracker.getXVelocity();
int yVelocity = (int)velocityTracker.getYVelocity();
注意,获取速度之前必须先计算速度,即调用computeCurrentVelocity方法,这里指的速度是指一段时间内手指滑过的像素数,1000指的是1000毫秒,得到的是1000毫秒内滑过的像素数。速度可正可负:1
速度 = (终点位置 - 起点位置) / 时间段
最后,当不需要使用的时候,需要调用clear()方法重置并回收内存:1
2velocityTracker.clear();
velocityTracker.recycle();
GestureDetector
手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。 使用方法:
1.创建一个GestureDetector对象并实现OnGestureListener接口,根据需要,也可实现OnDoubleTapListener接口从而监听双击行为:1
2
3GestureDetector mGestureDetector = new GestureDetector(this);
//解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongpressEnabled(false);
2.在目标View的OnTouchEvent方法中添加以下实现:1
2boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
3.实现OnGestureListener和OnDoubleTapListener接口中的方法,其中常用的方法有:onSingleTapUp(单击)、onFling(快速滑动)、onScroll(拖动)、onLongPress(长按)和onDoubleTap(双击)。 建议:如果只是监听滑动相关的,可以自己在onTouchEvent中实现,如果要监听双击这种行为,那么就使用GestureDetector。
Scroller
弹性滑动对象,用于实现View的弹性滑动。其本身无法让View他行滑动,需要和View的computeScroll方法配合使用才能完成这个功能。 使用方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Scroller scroller = new Scroller(mContext);
//缓慢移动到指定位置
private void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms内滑向destX,效果就是慢慢滑动
mScroller.startScroll(scrollX,0,delta,0,1000);
invalidata();
}
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX,mScroller.getCurrY());
postInvalidate();
}
}
参考资料:
《Android第一行代码》
Android自定义View之View的位置参数
android中getLocationInWindow和getLocationOnScreen的区别