全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Android事件分发机制(下) View的事件处理

综述

  在上篇文章Android中的事件分发机制(上)——ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析。在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View。并交由子View进行处理。那么现在就来分析一下子View接收到事件以后是如何处理的。

View的事件处理

  对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元素。这也就意味着View无法再次向下对事件进行分发操作,因此在View中并不存在onInterceptTouchEvent方法,也不会对事件做出拦截操作。它所做的事情就是对所接收的事件进行处理。下面就开看一下View如何对事件进行处理的。
  既然ViewGroup将事件交由View的dispatchTouchEvent方。那么首先在这里就来看一下dispatchTouchEvent里面做了什么事情。

public boolean dispatchTouchEvent(MotionEvent event) {

  ......

  if (onFilterTouchEventForSecurity(event)) {
    //noinspection SimplifiableIfStatement
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnTouchListener != null
        && (mViewFlags & ENABLED_MASK) == ENABLED
        && li.mOnTouchListener.onTouch(this, event)) {
      result = true;
    }

    if (!result && onTouchEvent(event)) {
      result = true;
    }
  }

  ......

  return result;
}

  在View的dispatchTouchEvent方法中对事件处理的核心部分体现在上述代码中。onFilterTouchEventForSecurity方法表示当前接收事件的view是否处于被遮盖状态,View处于被遮盖状态表示当前View不位于顶部,该view被其它View所覆盖。如果当前View被遮盖,那么该View不会对事件进行处理。

public interface OnTouchListener {
  boolean onTouch(View v, MotionEvent event);
}

public void setOnTouchListener(OnTouchListener l) {
  getListenerInfo().mOnTouchListener = l;
}

ListenerInfo getListenerInfo() {
  if (mListenerInfo != null) {
    return mListenerInfo;
  }
  mListenerInfo = new ListenerInfo();
  return mListenerInfo;
}

  在结合上述一段代码可以看到,通过setOnTouchListener方法设置OnTouchListener以后,若是当前View处于可用状态,那么条件li != null && li.mOnTouchListener !=null && (mViewFlags & ENABLED_MASK) == ENABLED必然为true。这时候程序便会回调OnTouchListener中的onTouch方法,若是在onTouch方法中返回true,便不会在执行View的onTouchEvent方法。从这里我们能够看到,一旦设置了OnTouchListener,那么OnTouchListener的优先级要高于onTouchEvent。
  有一点需要注意,在程序中设置了OnTouchListener以后,对于OnTouchListener中的onTouch的返回值并不代表View中的dispatchTouchEvent方法所返回的值。在onTouch方法返回true的时候,表示事件成功被当前View所消耗,这时候result被置为true并且不再执行onTouchEvent,所以dispatchTouchEvent也就返回true。可是一旦在onTouch方法中返回false。这时候便会调用onTouchEvent方法,如果事件被onTouchEvent成功处理,并返回true,result依然会被置为true,dispatchTouchEvent自然而然的也就返回true。
  下面在进入View的onTouchEvent方法一探究竟。对于onTouchEvent方法里的内容比较多,在这里分段查看。

if ((viewFlags & ENABLED_MASK) == DISABLED) {
  if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
    setPressed(false);
  }
  // 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)
      || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
}

  在这里可以看出对于不可用的View,如果他们的一些点击事件可用的话,依然能够成功的消费事件,只是它不会为该事件做出响应。对于View的这些点击之间默认为不可用,但是对于不同的的View他们的默认值不一样。例如在ImageView中点击事件依然为不可用,但是在Button中点击事件为可用。当然如果手动为它们设置监听事件,那么这些监听事件都将会自动被设为可用状态。从如下源码中可以看出。

public void setOnClickListener(@Nullable OnClickListener l) {
  if (!isClickable()) {
    setClickable(true);
  }
  getListenerInfo().mOnClickListener = l;
}

public void setOnLongClickListener(@Nullable OnLongClickListener l) {
  if (!isLongClickable()) {
    setLongClickable(true);
  }
  getListenerInfo().mOnLongClickListener = l;
}

public void setOnContextClickListener(@Nullable OnContextClickListener l) {
  if (!isContextClickable()) {
    setContextClickable(true);
  }
  getListenerInfo().mOnContextClickListener = l;
}

  下面接着看OnTouchEvent里面代码。

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

  这里首先判断是否对事件设置了代理,如果对事件设置了代理,便会执行TouchDelegate的onTouchEvent方法。mTouchDelegate默认值为null,可以通过View的setTouchDelegate方法来设置代理。对于TouchDelegate在后续的文章中在进行详细分析,在这里就不在过多描述。
  最后看一下View是如何处理事件的,对于接收的事件整个处理过程比较复杂,在这里就从宏观上来整体看一下它的处理机制。

if (((viewFlags & CLICKABLE) == CLICKABLE ||
    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
    (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
  switch (action) {
    case MotionEvent.ACTION_UP:

      ......

        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
          // 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();
            }
            if (!post(mPerformClick)) {
              performClick();
            }
          }
        }

      ......

      break;

    ......

  }

  return true;
}

  如果View的点击事件处于可用状态的话,便会对于这些事件进行处理,并且返回true。当一个事件序列完成以后调用performClick方法,下面看下这个performClick方法。

public boolean performClick() {
  final boolean result;
  final ListenerInfo li = mListenerInfo;
  if (li != null && li.mOnClickListener != null) {
    playSoundEffect(SoundEffectConstants.CLICK);
    li.mOnClickListener.onClick(this);
    result = true;
  } else {
    result = false;
  }

  sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  return result;
}


  从上面代码中可以看出,如果我们设置了OnClickListener,便会调用它的onClick方法。从这一路下来我们可以看出对于View的onClick事件,在最后才会被调用,可见onClick的优先级是最低的。

总结

  在这里对View的事件处理做一下总结。在ViewGroup将事件分发到View以后。在View里面通过OnTouchListener的onTouch和View中的onTouchEvent这两个方法对事件进行处理。对于onTouch方法是View提供给用户的,方便用户自己处理触摸事件,而onTouchEvent是Android系统自己实现的接口。若是用户设置了OnTouchListener,Android系统会首先调用OnTouchListener的onTouch方法。若是在onTouch方法中返回true,就不在执行View的onTouchEvent方法。只有在onTouch中返回了false才会执行onTouchEvent。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Android事件分发机制  # View事件处理  # Android事件分发  # Android开发事件处理的代码如何写手摸手教程  # Android事件分发之View事件处理关键及示例分析  # Android XRecyclerView最简单的item点击事件处理  # 详解Android的两种事件处理机制  # Android 中 EventBus 的使用之多线程事件处理  # Android开发多手指触控事件处理  # 在这里  # 便会  # 可以看出  # 看一下  # 他们的  # 不可用  # 也就  # 才会  # 这时候  # 会对  # 就来  # 如何处理  # 这一  # 也不  # 将会  # 在这  # 设为  # 会在  # 它是  # 这也 


相关文章: 香港网站服务器数量如何影响SEO优化效果?  c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】  ,有什么在线背英语单词效率比较高的网站?  如何快速搭建高效可靠的建站解决方案?  建站主机与虚拟主机有何区别?如何选择最优方案?  已有域名能否直接搭建网站?  魔方云NAT建站如何实现端口转发?  如何快速配置高效服务器建站软件?  css网站制作参考文献有哪些,易聊怎么注册?  佛山企业网站制作公司有哪些,沟通100网上服务官网?  制作网站公司那家好,网络公司是做什么的?  建站之星伪静态规则如何设置?  网页设计网站制作软件,microsoft office哪个可以创建网页?  北京企业网站设计制作公司,北京铁路集团官方网站?  云南网站制作公司有哪些,云南最好的招聘网站是哪个?  如何用已有域名快速搭建网站?  mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?  移民网站制作流程,怎么看加拿大移民官网?  成都响应式网站开发,dw怎么把手机适应页面变成网页?  php json中文编码为null的解决办法  阿里云网站制作公司,阿里云快速搭建网站好用吗?  高端网站建设与定制开发一站式解决方案 中企动力  图册素材网站设计制作软件,图册的导出方式有几种?  如何在Golang中引入测试模块_Golang测试包导入与使用实践  建站之星收费标准详解:套餐费用及年费价格表一览  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  如何彻底卸载建站之星软件?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  宝塔Windows建站如何避免显示默认IIS页面?  如何使用Golang table-driven基准测试_多组数据测量函数效率  企业网站制作费用多少,企业网站空间一般需要多大,费用是多少?  制作公司内部网站有哪些,内网如何建网站?  Android自定义listview布局实现上拉加载下拉刷新功能  如何彻底删除建站之星生成的Banner?  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  宿州网站制作公司兴策,安徽省低保查询网站?  如何设计高效校园网站?  建站之星安装模板失败:服务器环境不兼容?  单页制作网站有哪些,朋友给我发了一个单页网站,我应该怎么修改才能把他变成自己的呢,请求高手指点迷津?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  建站VPS推荐:2025年高性能服务器配置指南  长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?  C#如何序列化对象为XML XmlSerializer用法  如何通过cPanel快速搭建网站?  建站主机CVM配置优化、SEO策略与性能提升指南  网站制作价目表怎么做,珍爱网婚介费用多少?  建站之星2.7模板快速切换与批量管理功能操作指南  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  建站三合一如何选?哪家性价比更高? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。