android屏幕点击事件的分发机制

最近研究了一下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,默认返回false4.一个事件按照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/falsetrue---传递
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值