• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android View事件分发机制

Android View事件分发机制

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android view事件,android view事件分发,android view滑动事件,android view点击事件,android view类等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android View事件分发机制


最近在开发中遇到view滑动冲突的问题,由于一开始就知道这个问题与view事件分发有关,之后在网上看了几篇关于事件分发的资料后,开发中遇到的问题很快便得到解决。
在这里总结一下我对view事件分发的理解。

首先,看下事件分发流程图:
这里写图片描述

Button事件演示

在对view的事件分发机制进行分析前,我们可以通过一个demo看看Button的事件处理的流程。
在布局文件中添加一个button控件,然后在代码中实现Button的setOnClickListener和setOnTouchListener方法,注册Click监听和Touch监听。

/**
 * button事件
 */
private void showButtonTouch() {
    mBtn = (Button) findViewById(R.id.btn);
    mBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "Button onClick");
        }
    });
    mBtn.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    Log.e(TAG, "Button onTouch " + "ACTION_UP");
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.e(TAG, "Button onTouch " + "ACTION_MOVE");
                    break;
                case MotionEvent.ACTION_DOWN:
                    Log.e(TAG, "Button onTouch " + "ACTION_DOWN");
                    break;
            }

            return false;
        }
    });
}



    

demo运行起来之后点击button,看下log日志(在点击时移动一下保证ACTION_MOVE事件能被触发):
这里写图片描述

在这里通过日志可以看出事件处理的流程。

View事件分发源码解析

在View的源码中,我们可以看到dispatchTouchEvent方法,这个方法可以理解为是View事件分发的入口。(代码基于4.0.3即API 15,建议大家在理解源码时不要看太高的版本,高版本源码会有过多的优化,会妨碍我们对于代码主要功能逻辑的理解)

dispatchTouchEvent方法解析

以下是View中dispatchTouchEvent方法代码:

public boolean dispatchTouchEvent(MotionEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onTouchEvent(event, 0);
    }

    if (onFilterTouchEventForSecurity(event)) {
        //noinspection SimplifiableIfStatement

        //这个是View事件分发的主要逻辑判断
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            return true;
        }

        if (onTouchEvent(event)) {
            return true;
        }
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    }
    return false;
}

在这整个方法中,事件分发的关键就在这个判断中 (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) 。

如果这个判断为true,那么该方法返回true;否则,执行onTouchEvent()方法并根据onTouchEvent方法的返回值返回具体结果。

li != null:代码中ListenerInfo对象li,是View内定义的一个静态类,这个类内部定义了View中所有Listener相关的类,一般情况下这个类不为空,在这里不做过多解释(2.3版本源码中没有该对象)。

li.mOnTouchListener != null:是否为空,mOnTouchListener 对象就是我们通过mBtn.setOnTouchListener(new View.OnTouchListener() {})设置的,所以这里不为空。

(mViewFlags & ENABLED_MASK) == ENABLED:判断控件是否是enable,很显然为true。

li.mOnTouchListener.onTouch(this, event):最后就是判断onTouch方法中返回值是否为true,onTouch方法就是我们在Button控件注册Touch监听时@Override的onTouch方法。

在前面的demo中,因为mOnTouchListener.onTouch(this, event)方法的返回值为false,我们在log中看到button先执行touch事件在执行click事件。在这里我们将onTouch方法的返回值改为true,可以看到以下log:
这里写图片描述

在log中可以看到click方法没有被执行,这又是为什么呢?

其实在这里大家通过阅读dispatchTouchEvent方法代码可以想到,因为onTouch返回值为true,所以这个判断条件成立即dispatchTouchEvent方法返回true。if (onTouchEvent(event))->onTouchEvent方法没有被执行,会不会是由于这个原因导致click方法没有被执行呢? 很显然我们要看看onTouchEvent方法的源码。

onTouchEvent源码解析:

以下是onTouchEvent方法的源码:

public boolean onTouchEvent(MotionEvent event) {
    final int viewFlags = mViewFlags;

    if ((viewFlags & ENABLED_MASK) == DISABLED) {
        if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PRESSED) != 0) {
            mPrivateFlags &= ~PRESSED;
            refreshDrawableState();
        }
        // A disabled view that is clickable still consumes the touch
        // events, it just doesn't respond to them.
        return (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
    }

    if (mTouchDelegate != null) {
        if (mTouchDelegate.onTouchEvent(event)) {
            return true;
        }
    }


    //这是onTouchEvent代码主要逻辑功能
    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
                if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
                    // take focus if we don't have it already and we should in
                    // touch mode.
                    boolean focusTaken = false;
                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                        focusTaken = requestFocus();
                    }

                    if (prepressed) {
                        // The button is being released before we actually
                        // showed it as pressed.  Make it show the pressed
                        // state now (before scheduling the click) to ensure
                        // the user sees it.
                        mPrivateFlags |= PRESSED;
                        refreshDrawableState();
                   }

                    if (!mHasPerformedLongPress) {
                        // This is a tap, so remove the longpress check
                        removeLongPressCallback();

                        // Only perform take click actions if we were in the pressed state
                        if (!focusTaken) {
                            // Use a Runnable and post this rather than calling
                            // performClick directly. This lets other visual state
                            // of the view update before click actions start.
                            if (mPerformClick == null) {
                                mPerformClick = new PerformClick();




 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android事件分发
  • Android View事件分发机制

相关文章

  • 2017-05-26日志文件之出错处理
  • 2017-05-26仿天天动听5应用项目源码,项目源码
  • 2017-05-26SQLite 在 Android 的应用,sqliteandroid应用
  • 2017-05-26Java时间间隔问题在Android中的使用,javaandroid
  • 2017-05-26高仿360手机卫士应用源码,高仿360卫士源码
  • 2017-05-26TabLayout + ViewPager,tablayoutviewpager
  • 2017-05-26Android开发:Android SDK的介绍
  • 2017-05-26安卓当下最流行的吸顶效果的实现(转),安卓当下
  • 2017-05-26使用flume+kafka+storm构建实时日志分析系统
  • 2017-05-26android launchmode 使用场景

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 2.4.6 BaseAdapter优化
    • GreenDao 数据库:使用Raw文件夹下的数据库文件以及数据库升级,greendaoraw
    • Android 用Canvas画textview、bitmap、矩形(裁剪)、椭圆、线、点、弧
    • PostgreSql数据库的神器 FDW
    • Android中BroadcastReceiver的两种注册方式(静态和动态)详解,broadcastreceiver
    • Android 5.0 Settings源码简要分析
    • Android Volley框架的使用(5),androidvolley
    • 手游助手应用源码项目,游助手源码项目
    • 日志文件之出错处理
    • Play 2D games on Pixel running Android Nougat (N7.1.2) with Daydream View VR headset,nougatn7.1.2

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有