view的4个属性: top, left, right, bottom. 这4个属性值都是相对于父容器来说的, 因此它是一个相对坐标.
从android3.0开始,为view的左上角额外增加了几个参数, x, y, translationX和translationY. 当view在平移过程中, top和left表示的是原始左上角的位置信息,其值不改变, 改变的是x, y, translationX和translationY这4个参数.
MotionEvent点击事件
MotionEvent对象提供两组方法: getX/getY和getRawX/getRawY. getX/getY返回的是点击事件相对所在view左上角的坐标位置, 而getRawX/getRawY返回的是点击事件相对手机屏幕左上角的绝对坐标位置。
view的事件分发机制
事件分发机制还是比较复杂的, 看了1天多, 没能系统的把知识点总结完善, 那么就对应用开发中涉及到的点进行下总结吧.
事件分发机制,即当一个MotionEvent对象产生以后, 系统需要把这个对象传递给一个具体的view, 这个传递过程就是事件分发过程。分发过程由三个重要的方法来共同完成:
dispatchTouchEvent, onInterceptTouchEvent和onTouchEvent.
用户的一个触屏操作,叫做一个gesture, 产生一系列motionEvent对象,以ACTION_UP的motionEvent对象开始,以ACTION_DOWN的motionEvent对象结束, 中间可能有若干个ACTION_MOVE的motionEvent对象。
ViewGroup默认不拦截任何事件,它的onInterceptTouchEvent()直接返回false.
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
onInterceptTouchEvent()定义是在ViewGroup中, view类中没有onInterceptTouchEvent()的定义.
对于view来说:
view接受MotionEvent对象的入口是dispatchTouchEvent(), 负责调用mOnTouchListener.onTouch if it's defined, 如果mOnTouchListener不存在或是mOnTouchListener.onTouch返回的是false, 那么还会再调用onTouchEvent(event)。
对于ViewGroup来说:
ViewGroup接受MotionEvent对象的入口是dispatchTouchEvent(),做2件事,
- 首先调用onInterceptTouchEvent(ev),返回true的话,那么在ViewGroup这层做事件处理,不把事件分发到子view中, 调用自己的 onTouchListener.onTouch (if defined) or onTouchEvent() if (onTouchListener or onTouchListener.onTouch return false).
- 如果onInterceptTouchEvent(ev)返回false(也就是所有ViewGroup默认的返回值), 做hit test,遍历所有子views, 根据motionEvent的x,y查找对应的子view, 调用子view的dispatchTouchEvent(event).
开发中一个典型的问题是, 自定义view的onTouchEvent(event)返回值应该返回true还是返回false? 返回不同的值会产生什么效果.
对触屏事件的处理是以一个gesture为一个处理单元. 如果在处理ACTION_DOWN时返回true,那么这个gesture后续的motionEvent对象还会传递到当前view的onTouchEvent()处理, 如果在处理某一个motionEvent对象时,onTouchEvent()返回的是false,那么这个gesture后续的motionEvent对象就不会再传递到当前view的onTouchEvent().
结论是:
onTouchEvent()的返回值表示的含义是, 在处理完当前motionEvent对象后,这个gesture后续的一系列的motionEvent对象, 还要不要继续传递到当前view的onTouchEvent()中去处理. 返回true代表的是要, 返回false代表的是不要.
onTouchEvent()的返回值还表示另一层含义, 如果return true,系统对这个motionEvent对象的处理到此就结束了,如果return false,当前view的parent view(也就是一个ViewGroup)的onTouchEvent()会继续处理这个motionEvent对象.
view的onTouchEvent()对一个gesture的处理,是以处理ACTION_DOWN的motionEvent对象为开始点.
两个总结的很好的帖子, 帮助我们能够更清晰的了解事件分发机制。
http://stackoverflow.com/questions/9586032/android-difference-between-onintercepttouchevent-and-dispatchtouchevent
http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/
摘录:
The default case
Assuming that none of our Views override the default event handling behavior, this is what happens:
The DOWN event is passed to View C's onTouchEvent method. This method returns false, meaning "I don't care about this gesture."
Because of this, the DOWN event is passed to ViewGroup B's onTouchEvent method, which doesn't care about the gesture either and thus returns false as well.
Same thing: Because ViewGroup B didn't care, the event is now passed to ViewGroup A's onTouchEvent, which also returns false.
Because none of the Views cared about the event, they will not receive any events from the rest of this gesture.