当前位置: 首页 > news >正文

陕西金顶建设公司网站在社交网站开发外国客户

陕西金顶建设公司网站,在社交网站开发外国客户,做网站和app有什么区别,小学毕业个人主页设计概述 在介绍点击事件规则之前#xff0c;我们需要知道我们分析的是MotionEvent#xff0c;即点击事件#xff0c;所谓的事件分发就是对MotionEvent事件的分发过程#xff0c;即当一个MotionEvent生成以后#xff0c;系统需要把这个事件传递给具体的View#xff0c;而这个…概述 在介绍点击事件规则之前我们需要知道我们分析的是MotionEvent即点击事件所谓的事件分发就是对MotionEvent事件的分发过程即当一个MotionEvent生成以后系统需要把这个事件传递给具体的View而这个传递过程就是分发过程MotionEvent我们上节已经介绍过 事件分发主要涉及以下几个方法 dispatchTouchEvent用来进行事件的分发如果事件可以传递到当前View那么此方法一定会被调用返回结果受当前View的onTouchEvent和子View的dispatchTouchEvent方法影响表示是否消耗当前事件onInterceptTouchEvent在上个方法内部调用用来判断是否拦截事件如果当前View拦截了事件那么在同一时间序列内此方法不会再次被调用返回结果表示是否拦截事件onTouchEvent:在dispatchTouchEvent方法中调用用于事件的处理返回值表示是否消耗事件如果不消耗当前View无法再次接受到事件这三个方法到底有什么关系 我们先简述一下他们之间的关系之后再进行源码的详细分析 当一个事件传递给一个根ViewGroup之后这时他的dispatchTouchEvent就会被调用进行事件的分发如果该ViewGroup的onInterceptTouchEvent返回true表示他要拦截此事件接着这个事件就会交给ViewGroup处理即他的onTouchEvent就会被调用如果他的onInterceptTouchEvent返回fasle就表示不拦截此事件这时就会把此事件传递给他的子View接着子View的dispatchTouchEvent就会被调用如此反复直到事件最终被处理 源码分析 当一个事件产生后他的传递遵循如下顺序Activity→Window→View即事件总是县传递给Activity然后Activity传递给Window最后Window传递给顶级View顶级View接收到事件后就会按照事件分发机制分发事件 Activity对事件的分发 当一个点击操作发生时事件最先传递给当前的Activity由Activity的dispatchTouchEvent进行分发我们看下Activity的dispatchTouchEvent的源码 public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() MotionEvent.ACTION_DOWN) {onUserInteraction();}if (getWindow().superDispatchTouchEvent(ev)) {return true;}return onTouchEvent(ev);} 复制代码上面代码表示Activity会把事件交给Window处理如果Window的分发返回true表示事件就此结束返回false表示没有人处理那么Activity的onTouchEvent就会被调用 Window对事件的分发 那么Window是怎么分发事件的呢我们看下Window的源码我们发现Window其实是一个抽象类superDispatchTouchEvent也是一个抽象方法 public abstract boolean superDispatchTouchEvent(MotionEvent event); 复制代码那么Window的实现类是什么其实是PhoneWindow那我们看一下PhoneWindow是怎么处理事件的 Overridepublic boolean superDispatchTouchEvent(MotionEvent event) {return mDecor.superDispatchTouchEvent(event);} 复制代码PhoneWindow直接把事件交给了DecorViewDecorView其实就是最顶层的View我们setContentView的View就是DecorView的一个子ViewDecorView继承自FrameLayout这个时候事件已经分发到了ViewGroup上 ViewGroup事件的分发 现在我们看一下ViewGroup的dispatchTouchEvent方法的源码 Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {... //--------TAG1-------------------这里是一开始---------------------------------------------------//如果是Action_down 就对其先前所有的状态进行重置if (actionMasked MotionEvent.ACTION_DOWN) {cancelAndClearTouchTargets(ev);resetTouchState();} //--------TAG2-----------------这里开始进行拦截验证-----------------------------------------------//如果是ACTION_DOWN或者mFirstTouchTarget ! null就进行拦截验证final boolean intercepted;if (actionMasked MotionEvent.ACTION_DOWN|| mFirstTouchTarget ! null) {final boolean disallowIntercept (mGroupFlags FLAG_DISALLOW_INTERCEPT) ! 0;if (!disallowIntercept) {intercepted onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted false;}} else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted true;} //------------------------------------------------------------------------------------------------------------------------------....//----------TAG3----------------这里看是遍历子view---------------------------------------------------------------//如果不拦截并且不是cancel事件就进行遍历子view分发事件if (!canceled !intercepted) {...//当ACTION_DOWN和ACTION_POINTER_DOWN和ACTION_HOVER_MOVE时候才会遍历子viewif (actionMasked MotionEvent.ACTION_DOWN|| (split actionMasked MotionEvent.ACTION_POINTER_DOWN)|| actionMasked MotionEvent.ACTION_HOVER_MOVE) {//找到可以接受触摸事件孩子从前向后遍历查找final View[] children mChildren;for (int i childrenCount - 1; i 0; i--) {final int childIndex getAndVerifyPreorderedIndex(childrenCount, i, customOrder);final View child getAndVerifyPreorderedView(preorderedList, children, childIndex);...//判断触摸点是否在此View的范围中,是否在移动if (!canViewReceivePointerEvents(child)|| !isTransformedTouchPointInView(x, y, child, null)) {ev.setTargetAccessibilityFocus(false);continue;}...//分发事件如果事件被子view消费就跳出循环不再继续分发给其他viewif (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {...//addTouchTarget内部赋值mFirstTouchTarget当前viewnewTouchTarget addTouchTarget(child, idBitsToAssign);alreadyDispatchedToNewTouchTarget true;break;}} //-----------TAG4-----------------这里已经遍历完了子view--------------------------------------------// //遍历完所有的子View后还没有处理事件就自己处理if (mFirstTouchTarget null) {// No touch targets so treat this as an ordinary view.handled dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} else {//Action_Down之外的事件直接分发给目标viewTouchTarget predecessor null;TouchTarget target mFirstTouchTarget;while (target ! null) {final TouchTarget next target.next;//如果上方遍历已经传递过改事件则跳过本次事件if (alreadyDispatchedToNewTouchTarget target newTouchTarget) {handled true;} else {final boolean cancelChild resetCancelNextUpFlag(target.child)|| intercepted;if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {handled true;}...}} //------------------------------------------------------------------------------------------------------------------------------// Update list of touch targets for pointer up or cancel, if needed.if (canceled|| actionMasked MotionEvent.ACTION_UP|| actionMasked MotionEvent.ACTION_HOVER_MOVE) {resetTouchState();} else if (split actionMasked MotionEvent.ACTION_POINTER_UP) {final int actionIndex ev.getActionIndex();final int idBitsToRemove 1 ev.getPointerId(actionIndex);removePointersFromTouchTargets(idBitsToRemove);}}if (!handled mInputEventConsistencyVerifier ! null) {mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);}return handled;} 复制代码首先我们分析一下拦截事件的源码 //如果是ACTION_DOWN或者mFirstTouchTarget ! null就进行拦截验证final boolean intercepted;if (actionMasked MotionEvent.ACTION_DOW || mFirstTouchTarget ! null) {final boolean disallowIntercept (mGroupFlags FLAG_DISALLOW_INTERCEPT) ! 0;if (!disallowIntercept) {intercepted onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted false;}} else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted true;} 复制代码这段代码我们可以看到有俩种情况会判断是否要拦截当前事件事件类型是Action_Down,或者mFirstTouchTarget ! nullACTION_DOWN我们可以理解mFirstTouchTarget ! null代表什么呢 我们从后面的代码可以看出事件由ViewGroup的子元素处理成功时mFirstTouchTarget被赋值并指向该子元素也就是说当ViewGroup不拦截事件交由子元素处理时mFirstTouchTarget ! null 一旦ViewGroup拦截事件mFirstTouchTarget ! null就不成立而当ACTION_MOVE ,ACTION_UP到来时由于(actionMasked MotionEvent.ACTION_DOWN|| mFirstTouchTarget ! null)这个判断为falseViewGroup的onInterceptTouchEvent不在会被调用并且同一序列的其他事件会默认交给ViewGroup处理 这里还有一种特殊情况FLAG_DISALLOW_INTERCEPT标志位这个标志位是通过requestDisallowInterceptTouchEvent来设置的一般用于子View中一旦FLAG_DISALLOW_INTERCEPT标志为被设置后ViewGroup将无法拦截除了ACTION_DOWN之外的其他事件为什么要除了ACTION_DOWN呢因为每当ACTION_DOWN带来都会重置FLAG_DISALLOW_INTERCEPT这个标记位ACTION_DOWN事件总会调用自己的onInterceptTouchEvent询问是否拦截 强调一点requestDisallowInterceptTouchEvent这个方法并不是万能的执行他的前提是子View必须获取事件假如父View的Down事件的onInterceptTouchEvent就返回true拦截事件那么子View做任何操作也不可能获取到事件 从上面分析我们可以得出结论 当ViewGroup决定拦截事件的时候那么后续的点击事件将默认交给他不再调用onInterceptTouchEventFLAG_DISALLOW_INTERCEPT作用是让ViewGroup不再拦截事件前提是ViewGroup不拦截Action_Down事件onInterceptTouchEvent不是每次都会调用的如果我们要提前处理点击事件需要在dispatchTouchEvent当我们遇到滑动冲突的时候可以考虑FLAG_DISALLOW_INTERCEPT来处理我们看一下ViewGroup不拦截的事件的情况 先看一下源码这个是删减后的源码看起来比较清楚 //如果不拦截并且不是cancel事件就进行遍历子view分发事件if (!canceled !intercepted) {...//当ACTION_DOWN和ACTION_POINTER_DOWN和ACTION_HOVER_MOVE时候才会遍历子viewif (actionMasked MotionEvent.ACTION_DOWN|| (split actionMasked MotionEvent.ACTION_POINTER_DOWN)|| actionMasked MotionEvent.ACTION_HOVER_MOVE) {//找到可以接受触摸事件孩子从前向后遍历查找final View[] children mChildren;for (int i childrenCount - 1; i 0; i--) {final int childIndex getAndVerifyPreorderedIndex(childrenCount, i, customOrder);final View child getAndVerifyPreorderedView(preorderedList, children, childIndex);...//判断触摸点是否在此View的范围中,是否在移动if (!canViewReceivePointerEvents(child)|| !isTransformedTouchPointInView(x, y, child, null)) {ev.setTargetAccessibilityFocus(false);continue;}...//分发事件如果事件被子view消费就跳出循环不再继续分发给其他viewif (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {...//addTouchTarget内部赋值mFirstTouchTarget当前viewnewTouchTarget addTouchTarget(child, idBitsToAssign);alreadyDispatchedToNewTouchTarget true;break;}} 复制代码首先遍历ViewGroup的所有子元素然后判断判断子元素是否能接收到点击事件是否能接收到点击事件主要由俩点来衡量 点击的坐标是否落在了子元素的区域内子元素是否在播放动画如果子元素满足这俩个条件那么事件将传递给他处理分发事件其实dispatchTransformedTouchEvent是这个方法做的我们看一下dispatchTransformedTouchEvent源码 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,View child, int desiredPointerIdBits) {final boolean handled;//先记住这一段判断cancel的源码很重要下面分析if (cancel || oldAction MotionEvent.ACTION_CANCEL) {event.setAction(MotionEvent.ACTION_CANCEL);if (child null) {handled super.dispatchTouchEvent(event);} else {handled child.dispatchTouchEvent(event);}event.setAction(oldAction);return handled;}....if (child null) {handled super.dispatchTouchEvent(event);} else {...handled child.dispatchTouchEvent(event);}.....return handled;} 复制代码这里面主要代码如果 if (cancel || oldAction MotionEvent.ACTION_CANCEL) 为false这个判断的意思是如果不是ACTION_CANCEL外部传入的cancel也为fasle就进行下面的判断而下面的判断主要是根据传入的child是否为null来判断的如果child不为null那么就调用child的dispatchTouchEvent方法这个事件就交给子元素去处理这就完成一轮的事件分发 如果child的dispatchTouchEvent返回为true先不考虑事件怎么在子元素中分发那么mFirstTouchTarget就被赋值跳出for循环 //分发事件如果事件被子view消费就跳出循环不再继续分发给其他viewif (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {...//addTouchTarget内部赋值mFirstTouchTarget当前viewnewTouchTarget addTouchTarget(child, idBitsToAssign);alreadyDispatchedToNewTouchTarget true;break;} 复制代码上面的代码完成了给mFirstTouchTarget赋值并且跳出for循环终止对子元素的遍历如果子元素的dispatchTouchEvent返回fasle那么就会继续遍历子元素把事件传递给下一个合适的子元素如果还有合适的子元素的话 mFirstTouchTarget赋值是在addTouchTarget方法内部完成的,mFirstTouchTarget是一个单链表结构 private TouchTarget addTouchTarget(NonNull View child, int pointerIdBits) {final TouchTarget target TouchTarget.obtain(child, pointerIdBits);//注意这里这里很重要target.next null然后 mFirstTouchTarget target;也就是说这时候的 mFirstTouchTarget.nextnulltarget.next mFirstTouchTarget;mFirstTouchTarget target;return target;} 复制代码如果遍历所有的子元素事件都没有合适的处理这里包含俩种情况一种就是ViewGroup没有子元素第二种就是子元素的dispatchTouchEvent返回了fasle这俩种情况下ViewGroup会自己处理事件 //遍历完所有的子View后还没有处理事件就自己处理if (mFirstTouchTarget null) {handled dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} 复制代码注意这里child参数传入的是null根据之前的分析就会调用 super.dispatchTouchEvent(event);由于ViewGroup也是继承自View这里就会转到View的dispatchTouchEvent即点击事件交给View处理 注意敲黑板了啊 我看了很多博客都没有对这种情况进行分析这个问题一度卡了我很久 现在考虑一种情况如果父View的onInterceptTouchEvent的Down事件返回false不拦截move up事件返回true拦截这个效果就是子View只能收到Down事件而收不到Up和Move事件 那么我们现在分析一下这种情况按照我们上方的分析父View的Down事件不拦截那么mFirstTouchTarget就会被赋值第二次Move和Up事件要拦截但是由于mFirstTouchTarget被赋值了所以是走不到下面这步的 // //遍历完所有的子View后还没有处理事件就自己处理if (mFirstTouchTarget null) {// No touch targets so treat this as an ordinary view.handled dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} 复制代码那么父View是怎么拦截Move和Up事件的呢 当地一个Move事件传递给父View后此时mFirstTouchTarget不为null所以走拦截这一步代码 //如果是ACTION_DOWN或者mFirstTouchTarget ! null就进行拦截验证final boolean intercepted;if (actionMasked MotionEvent.ACTION_DOW || mFirstTouchTarget ! null) {final boolean disallowIntercept (mGroupFlags FLAG_DISALLOW_INTERCEPT) ! 0;if (!disallowIntercept) {intercepted onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted false;}} else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted true;} 复制代码拦截返回true后不走遍历子Vew代码直接到最后的判断代码 // //遍历完所有的子View后还没有处理事件就自己处理if (mFirstTouchTarget null) {// No touch targets so treat this as an ordinary view.handled dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} else {//Action_Down之外的事件直接分发给目标viewTouchTarget predecessor null;TouchTarget target mFirstTouchTarget;while (target ! null) {final TouchTarget next target.next;//如果上方遍历已经传递过改事件则跳过本次事件if (alreadyDispatchedToNewTouchTarget target newTouchTarget) {handled true;} else {final boolean cancelChild resetCancelNextUpFlag(target.child)|| intercepted;if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {handled true;}if (cancelChild) {if (predecessor null) {mFirstTouchTarget next;} else {predecessor.next next;}target.recycle();target next;continue;}}} 复制代码由于mFirstTouchTarget在Down的时候已经赋值不为null会走下边代码 final boolean cancelChild resetCancelNextUpFlag(target.child)|| intercepted; 复制代码由于拦截事件cancelChild为true也就是说下面这个分发dispatchTransformedTouchEvent的方法传入的是true if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {handled true;} 复制代码在这个分发方法里有判断Cancel事件的代码 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,View child, int desiredPointerIdBits) {final boolean handled;//先记住这一段判断cancel的源码很重要下面分析if (cancel || oldAction MotionEvent.ACTION_CANCEL) {event.setAction(MotionEvent.ACTION_CANCEL);if (child null) {handled super.dispatchTouchEvent(event);} else {handled child.dispatchTouchEvent(event);}event.setAction(oldAction);return handled;}...return handled;} 复制代码由于传入的cancel为true 会重新定义事件为Cancel事件event.setAction(MotionEvent.ACTION_CANCEL);child不为null所以会调用child.dispatchTouchEvent(event);也就是说第一个Move事件父View不会拦截但会给子View发送一个Cancel事件 接下来会继续走代码 TouchTarget target mFirstTouchTarget;final TouchTarget next target.next; ...if (cancelChild) {...mFirstTouchTarget next;...} 复制代码上面已经分析过cancelChild为true进入方法给mFirstTouchTarget重新赋值mFirstTouchTarget.next,那么mFirstTouchTarget.next等于什么看下面一段代码 private TouchTarget addTouchTarget(NonNull View child, int pointerIdBits) {final TouchTarget target TouchTarget.obtain(child, pointerIdBits);//注意这里这里很重要target.next null然后 mFirstTouchTarget target;也就是说这时候的 mFirstTouchTarget.nextnulltarget.next mFirstTouchTarget;mFirstTouchTarget target;return target;} 复制代码其实mFirstTouchTarget.nextnull那整合起来就是把mFirstTouchTarget重新赋值为null从这里开始第二个Move事件就会直接传递给父View完成了拦截 if (mFirstTouchTarget null) {handled dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} 复制代码总结 当父View不拦截Down事件但要拦截Move和Up事件时第一个Move事件会重新赋值为Cancel事件发送给子View然后mFirstTouchTarget赋值为null第二次开始的Move事件就会交给父View View的事件分发源码 View对事件的处理比较简单注意这里的View不包括ViewGroup先看他的dispatchTouchEvent public boolean dispatchTouchEvent(MotionEvent event) {...boolean result false;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的时间传递比较简单因为View不包括ViewGroup是一个单独的元素无法向下传递事件所以没有onInterceptTouchEvent方法从上面源码可以看出 首先会判断与没有mOnTouchListener如果有并且其中的onTouch方法返回true那么onTouchEvent放方法不会调用可以看出mOnTouchListener的优先级高于onTouchEvent下面看一下onTouchEvent方法的源码 首先看一下当View处于不可用状态下事件的处理过程 final boolean clickable ((viewFlags CLICKABLE) CLICKABLE|| (viewFlags LONG_CLICKABLE) LONG_CLICKABLE)|| (viewFlags CONTEXT_CLICKABLE) CONTEXT_CLICKABLE;if ((viewFlags ENABLED_MASK) DISABLED) {if (action MotionEvent.ACTION_UP (mPrivateFlags PFLAG_PRESSED) ! 0) {setPressed(false);}mPrivateFlags3 ~PFLAG3_FINGER_DOWN;// A disabled view that is clickable still consumes the touch// events, it just doesnt respond to them.return clickable;} 复制代码可以看出不可用的状态下View消耗点击事件 再看一下对具体事件的处理 final boolean clickable ((viewFlags CLICKABLE) CLICKABLE|| (viewFlags LONG_CLICKABLE) LONG_CLICKABLE)|| (viewFlags CONTEXT_CLICKABLE) CONTEXT_CLICKABLE;if (clickable || (viewFlags TOOLTIP) TOOLTIP) {switch (action) {case MotionEvent.ACTION_UP:...if (mPerformClick null) {mPerformClick new PerformClick();}if (!post(mPerformClick)) {performClickInternal();}}}....case MotionEvent.ACTION_DOWN:...case MotionEvent.ACTION_CANCEL:...case MotionEvent.ACTION_MOVE:...break;}复制代码从上面代码为可以看出 只要View的CLICKABLE和LONG_CLICKABLE一个为true不管他是不是DISABLED状态都消耗事件只不过DISABLED不走下面的downup事件当Action_Up触发时会调用PerformClick方法如果View设置了onClickListener那么PerformClick将调用他的onClick方法View的LONG_CLICKABLE默认是false但是CLICKABLE是否为fasle跟具体View有关可点击的CLICKABLE为true不可点击的CLICKABLE为falsesetClickable和setLongClickable可以改变CLICKABLE和LONG_CLICKABLE的值setClickLinsterer和setLongClickLinsterer会自动设置CLICKABLE和LONG_CLICKABLE为true到这里事件分发就处理完了 参考Android开发艺术探索 allenfeng.com/2017/02/22/… 转载于:https://juejin.im/post/5d4d212d5188253afe4c8ada
http://www.huolong8.cn/news/130234/

相关文章:

  • 网站开发学的啥网站网站制作网站的
  • 石家庄专业网站制wordpress顶部高度
  • 拐角型网站华为云建站官网
  • 网站建设佰首选金手指十05网全部答案数学
  • 单页电影网站源码wordpress检验上传的文档
  • 办个网站多少钱房屋平面图在线制作网站
  • wordpress设置中改网站美食网站建设策划报告
  • 怎样建手机网站广州企业网站制作公司
  • 几度设计网站上海哪家公司做网站比较好
  • 网站建设中存在的问题东莞有哪些好的网站建设公司
  • 做网站需要什么费用怎么和网站主联系方式
  • 二级域名网站可以做关键词优化吗高端建造
  • 境外电商网站建设北仑静态网站建设
  • 传播公司可以做门户网站吗百度快照优化推广
  • 专业免费网站建设一般外汇网站建设制作
  • 做网站 怎么连到数据库wordpress app页面模板
  • 企业做可信网站认证的好处图床外链生成工具
  • 高港区企业网站建设wordpress图书页面
  • 云服务器网站解析凡科小程序建站官网
  • 韩国做暖暖网站html5做的网站代码
  • 郑州平台网站建设企业网站html5
  • 成都便宜网站建设公司哪家好wordpress柳城
  • 网站建设需要哪些材料如何避免网站被攻击
  • wordpress 仿站 教程网深圳网站建设公
  • 网站建设制作报价宜都网站设计
  • 排名好的网站关键词优化企业wordpress 官网主题下载
  • 网站如何设定关键词深圳前十名代运营公司
  • 常德海关网站app开发模板
  • 模板的网站都有哪些内容机构网站建设需要交费吗
  • 深圳网站开发费用如何细分行业 做网站赚钱