1.View的onTouchEvent()方法返回true和false有什么区别? SDK给出的解释很简单:"返回true代表该事件已经被处理过了,返回false则相反",这句话完全没有解释清楚问题。
2.View的onTouchEvent()方法在处理ACTION_DOWN的时候返回true,在处理ACTION_MOVE的时候返回false,代表着是处理了还是没处理?返回super.onTouchEvent()又是什么含义?
3.重写onTouchEvent()方法和通过setOnTouchListener()设置一个触屏监听有什么区别,看起来好像很类似。
4.View的dispatchTouchEvent(),onTouchEvent(),setOnClickListener(),ViewGroup的onInterceptTouchEvent()把我绕晕了,这些方法怎么使用怎么重写?
5.假设一个ViewGroup有两个子view,这两个view有一部分是重叠的,点击该重叠部分,事件由哪个View来处理?
6.Activity的onTouchEvent()和dispatchEvent()何时调用,怎么重写?
7.最重要的一点疑问是:触屏事件从顶层ViewGroup一直向下是怎么传递的?1.View一般是为了显示某些内容而存在的,它也通常用来处理用户的触屏等交互事件,而ViewGroup则是做为View的容器而存在的,虽然在代码上它是View的子类,但它通常只是做为容器用来组织它的子视图布局方式,默认情况下甚至ViewGroup的onDraw方法都不会被调用到,因为在ViewGroup的构造函数中设置了WILL_NOT_DRAW这个标志。
2.我们知道android里边View层次是一种树型结构,需要明确的是一个ViewGroup它的直接子视图才算是树结构中的儿子,再往下一层就不算了,类似于进程间的父子关系。举例,FrameLayout有两个子视图,分别是LinearLayout和TextView,而LinearLayout又有三个子视图ImageView,那么调用FrameLayout的getChildCount()方法只会返回2,而不是5。因此以下内容中"子视图"这个术语代表着一个ViewGroup的直接子视图,它即可能是一个View类,也可能是一个ViewGroup类。
3.Activity视图的最顶层View是DecorView,它是在PhoneWindow类中通过generateDecor()方法生成的,它继承自FrameLayout,是View层次的根视图。
4.对于触屏来说有三个主要的事件:down,move,up这里就不分析ViewGroup的dispatchTouchEvent()方法的代码了,直接给出我总结出来的结论,有兴趣的读者可以分析看看。
三.总结
以下情景假设一个ViewGroup有三个子视图,按index顺序为v1,v2,v3。v1也是一个ViewGroup,v2和v3都是普通的view,而且它们有一点重叠的部分。由上面结论,如果两视图是兄弟关系,它们又互有重叠部分,点击该重叠部分,先处理该事件的是下标比较大的那个视图,如果这个视图不想处理事件,才让另外一个处理。
四.onInterceptTouchEvent()
当然如果自己重写了ViewGroup的dispatchTouchEvent()方法就自己掌控了事件的分发过程,和上面的流程就不一定一样了。
五.Activity onTouchEvent()
事实上DecorView的dispatchTouchEvent会先调用Activity的dispatchTouchEvent,代码如下:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// Stylus events with side button pressed are filtered and other
// events are processed normally.
if (mEnableGestures
&& MotionEvent.BUTTON_SECONDARY == ev.getButtonState()) {
mStylusFilter.onTouchEvent(ev);
return false;
}
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
}
/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
它的getWindow()实际上引用的是PhoneWindow对象,又调用到了DecorView的superDispatchTouchEvent方法,而这个方法的作用就是上面所说的在View层次中进行事件的分发,如果有任何一个子视图处理了该事件,那么Activity的dispatchTouchEvent方法就返回true,否则会调用Activity的onTouchEvent方法。
注释上的说法是可以重写Activity的dispatchTouchEvent方法从而在分发事件之前拦截住所有事件。
六. mScrollX/mScrollY 与触屏坐标偏移
一个view可以通过scrollBy或者scrollTo对其内容产生滚动,这种滚动只对view的显示产生影响,不会影响到view的矩形框属性,mLeft,mTop等位置属性值不变,而且此view左上角触屏坐标仍然是(0,0)。
一个ViewGroup也可以通过scrollBy或者scrollTo对其内容产生滚动,由于滚动影响了子视图的显示位置(但是子视图mLeft,mTop等位置属性值仍然不变),因此需要对触屏坐标做调整,让子视图左上角触屏坐标始终是(0,0),这是通过如下代码来实现的:
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
event.offsetLocation(offsetX, offsetY);
handled = child.dispatchTouchEvent(event);
event.offsetLocation(-offsetX, -offsetY);
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- hzar.cn 版权所有 赣ICP备2024042791号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务