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

Android事件分发机制(下) View的事件处理,第1张

概述综述  在上篇文章Android中的事件分发机制(上)――ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析。在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将

综述

  在上篇文章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事件分发机制(下) View的事件处理所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1147236.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-31
下一篇2022-05-31

发表评论

登录后才能评论

评论列表(0条)

    保存