最近研究了一下android 屏幕中控件点击的分发机制,到底是如何实现的?????
为啥点击了屏幕就能响应,这么智能啊???
容器类控件和普通控件有什么区别???
容器类控件(如linearlayout)和里面的子控件(button)谁先响应这个点击事件????
touch事件和click事件到底有啥区别??
touch事件里面的down、move、up到底是怎么执行的???
话不多说直接给结论.
1、为啥点击了屏幕就能响应,有这么智能啊
首先android界面捕获事件的流程。用户在屏幕上点击一下后,
程序里面的OnClickListener是怎样收到这个事件的。
大致流程如下
用户点击-(硬件驱动部分)硬件产生一个中断,
往/dev/input/event*写入一个相应的信号->jni部分,android循环读取/dev/input/event*的事件,
再分发给WindowManagerServer,
最后再发到相应的ViewGroup和View。
这里可以通过往/dev/input/event*写信号的方式,
来达到模拟事件的目的,接下来关心的就是信号的协议了。
说到底就是一个硬件中断,我猜测是屏幕相当于一个感应器,
手点击了,会产生一个硬件中断信号,这个和底层硬件有关系了,
旧式的手机是点击实体按钮的,智能机器是点击屏幕了,
时代在进步啊,估计以后直接和人的大脑连接起来也说不定。。。
有人屏幕坏了,点击不能响应,就是这个原因,花钱换屏幕吧。。。
命令涉及到linux,android底层就是linux系统。
参考http://blog.youkuaiyun.com/fanjunjian1991/article/details/44648287
2、容器类控件和普通控件有什么区别
ViewGroup就是一组View的集合,它包含很多的子View和子VewGroup,
是android中所有布局的父类或间接父类,像LinearLayout、
RelativeLayout等都是继承自ViewGroup的。但ViewGroup实
际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。
package android.view;
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource{。。。}
package android.view;
public abstract class ViewGroup extends View implements ViewParent, ViewManager {。。。}
3、容器类控件(如linearlayout)和里面的子控件(button)谁先响应这个点击事件
1. Android事件分发是先传递到容器类控件ViewGroup,
2. 再由ViewGroup传递到子View的。
对事件传递进行拦截,
3. onInterceptTouchEvent方法
返回true代表不允许事件继续向子View传递;
返回false代表不对事件进行拦截,传递给你点击的那个子控件,
如button,默认返回false。
4.一个事件按照ViewGroup--->子View传递,
子View如果将传递的事件消费掉,ViewGroup就不再对该事
件进行处理了。当然,再传递过程中,ViewGroup肯定可以
对事件进行操作的,因为ViewGroup先拿到啊!!!
4、touch事件和click事件到底有啥区别
几个重要的方法:
ViewGroup布局类:
重写的public boolean dispatchTouchEvent(MotionEvent ev){
...
view的super.dispatchTouchEvent(ev)...
onInterceptTouchEvent(ev)拦截点击事件传递给孩子...
mOnTouchListener.onTouch(this, event)...
onTouchEvent(event);...
}
view(button、textview一类):
view的 public boolean dispatchTouchEvent(MotionEvent ev)
...
mOnTouchListener.onTouch(this, event)...
onTouchEvent(event);...
核心部分源码:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
所以对于button来说顺序
dispatchTouchEvent
onTouch
onLongClick可能执行
onTouchEvent 里面有onclick
1
touchdown touchmove(可能多次) onlonglick touchmove(可能多次) touchup onclick
2
touchdown onlonglick touchup onclick
3
touchdown onlonglick touchmove(可能多次) touchup onclick
4
touchdown touchmove(可能多次) onlonglick touchup onclick
从源码中可以看出,这两个方法都是在View的dispatchTouchEvent
中调用的,onTouch优先于onTouchEvent执行。
如果在onTouch方法中通过返回true将事件消费掉,
onTouchEvent将不会再执行。
另外需要注意的是,onTouch能够得到执行需要两
个前提条件,第一mOnTouchListener的值不能为空,
第二当前点击的控件必须
是enable的。因此如果你有一个控件是非enable的,
那么给它注册onTouch事件将永远得不到执行。对于这一类控件,
如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
5、touch事件里面的down、move、up到底是怎么执行的
onTouch的3个状态
ACTION_DOWN、
ACTION_MOVE与
ACTION_UP到底是怎么执行的???
给个总结,
顺序肯定是固定的,down---move(可能执行)---up(可能执行)
一句话调用三次view的dispatchTouchEvent(ev),相当于3个
不同的事件!!!每次执行完,给出一个true/false,
true---传递
false---消费事件,结束传递
前提父容器没有拦截事件分发:
点击按钮,必定执行一次控件(比如button)dispatchTouchEvent(ev),
执行ACTION_DOWN事件,如果dispatchTouchEvent返回true;
继续执行一次或者多次dispatchTouchEvent(ev),这个时候如果你手
指没有发抖会执行一次onLongClick方法,稍微移动一下会执行一
次ACTION_MOVE状态,非常敏感,执行很多次都正常,这个时候如果也是返回true;
如果你手指移开了,再执行一次dispatchTouchEvent(ev),
对应ACTION_UP,如果还是返回true;
会执行button的 onclick事件。
给一个demo,点击button后永远只执行一次ACTION_DOWN
CustomButton.java
package com.example.testtouch;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;
public class CustomButton extends Button {
int i = 1;
public CustomButton(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public CustomButton(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
Log.d("CustomButton", "dispatchTouchEvent 次数---" + i++);
Log.d("CustomButton", "dispatchTouchEvent---" + event);
// return super.dispatchTouchEvent(event);
return false;
}
}
MainActivity .java
package com.example.testtouch;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
CustomButton bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (CustomButton) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d("CustomButton", "onClick---" + v);
}
});
}
}
打印结果,点击一次返回
由于事件分发到了子View,点击button,执行顺序是
父容器dispatchTouchEvent(tv)
找到点击的子空间button
子控件的dispatchTouchEvent(tv)
但是我注释了
// return super.dispatchTouchEvent(event);
直接返回false,
终止事件分发
actionmove
actionup
onclick
onlongclick
都不会执行。。。
打印一次actiondown 的log,结束。
好了,文章参考郭神
http://blog.youkuaiyun.com/guolin_blog/article/details/9097463/
http://blog.youkuaiyun.com/guolin_blog/article/details/9153747
3073

被折叠的 条评论
为什么被折叠?



