View
- View的left,top,bottom,right对应于源码中的mLeft,mTop,mBottom,mRight,
是相对于父容器而言的。获取方式,getLeft(),getTop,getRight(),getBottom()
- 从Android 3.0开始,View增加了几个额外参数,x,y,translationX和translationY,也都是相对于父容器。
x,y是view的左上角坐标
translationX和translationY是相对于父容器的偏移量,默认值为0
关系:x= left+translationX, y=top+translationY
- 在平移过程中,top和left表示原始左上角坐标的位置,不会发生改变,发生改变的只有x,y,translationX,translationY.
- 通过MotionEvent可以获得点击事件发生的点的x,y坐标
getX()/getY() 获取相当于当前View左上角的坐标
getRawX()/getRowY() 返回相当于屏幕的左上角的坐标
- TouchSlop 系统所能识别出的被认为是滑动的最小距离 p125
获取方式:
ViewConfiguration.get(getContext()).getScaledTouchSlop();
- VelocityTracker 速度追踪,用于追踪手指在滑动过程中的速度。p126
- GestrueDetector 手势检测,用于辅助检测用户的单击滑动双击长按等行为
GestrueDetector mGestrueDetector = new GestrueDetector();
//解决长按屏幕后无法拖动现象
mGestrueDetector.setIsLongpressEnable(flase);
//接管目标View的onTouchEvent,在onTouchEvent中做如下处理
boolean consume = mGestrueDetector.onTouchEvent(event);
return consume;
- Scroller 弹性滑动对象
需要和View的computeScroll方法配合使用
Scroller scroller = new Scroller(getContext());
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms 内滑向 destX,效果就是慢慢滑动
scroller.startScroll(scrollX, 0, delta, 0, 1000);
invalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
- scrollTo,scrollBy只能改变View的内容位置,而不能改变View在布局中的位置
mScrollX指View左边缘到View内容左边缘的距离,mScrollY同理
View的左边缘在View内容左边缘的右边时,mScrollX值为正(从右向左滑动),View上边缘在View内容上边缘的下边时,mScroll值为正(从下往上滑动)。
获取方式:getScrollX(),getScrollY()
View事件分发机制
如果给一个View设置了onTouchListener,那么它的onTouchListener的onTouch方法会被调用,这时就看onTouch的返回值,如果返回false,则当前View的onTouchEvent会被调用,在onTouchEvent中,如果当前view设置有onClickListener,那么它的onClick方法会被调用
由此可见 onTouchListener>onTouchEvent>onClickListenr.
- requestDisallowInteceptTouchEvent()在子元素干预父元素的事件分发过程
- Activity的事件分发过程:
当一个点击事件发生时,事件最新传递给Activity的dispatchTouchEvent,由它来派发事件,具体会由Activity的Window来进行处理,Window会将事件传递给DecorView,decor view一般就是界面的底层容器,
Activity dispatchTouchEvent源码分析:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
如果返回了true则activity的dispatchTouchEvent也就执行完毕了,如果返回false,则交由activity onTouchEvent处理。
window中的分发是由其实现类phoneWindow来分发的。PhoneWindow直接将事件分发给DecorView(FrameLayout)
-
顶级容器对事件的分发过程
- View的onClick事件执行是在onTouchEvent中的ACTION_UP中执行的。