viewGroup事件分发记录
来源:互联网 发布:php 中英文混合截取 编辑:程序博客网 时间:2024/05/21 19:42
阅读鸿洋大神博客总结,供自己学习用
1.例子
自定义linearLayout
package com.miyapay.cspm.test01.view;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * Created by miya96 on 2016/12/2. */public class MyLinearLayout extends LinearLayout { private static final String TAG = MyLinearLayout.class.getSimpleName(); public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "dispatchTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "dispatchTouchEvent ACTION_UP"); break; default: break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouchEvent ACTION_UP"); break; default: break; } return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onInterceptTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onInterceptTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onInterceptTouchEvent ACTION_UP"); break; default: break; } return super.onInterceptTouchEvent(ev); } @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { Log.e(TAG, "requestDisallowInterceptTouchEvent "); super.requestDisallowInterceptTouchEvent(disallowIntercept); }}
复写了与事件分发相关的代码
主布局如下:
<?xml version="1.0" encoding="utf-8"?><com.miyapay.cspm.test01.view.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.miyapay.cspm.test01.view.MyButton android:id="@+id/mybutton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_gravity="center_horizontal" android:layout_marginTop="106dp" android:text="@string/button"/></com.miyapay.cspm.test01.view.MyLinearLayout>
直接运行,点击,move一下,logcat日志如下
MyLinearLayout: dispatchTouchEvent ACTION_DOWNMyLinearLayout: onInterceptTouchEvent ACTION_DOWNMyButton: dispatchTouchEvent ACTION_DOWNMyButton: onTouch ACTION_DOWNMyButton: onTouchEvent ACTION_DOWNMyLinearLayout: dispatchTouchEvent ACTION_MOVEMyLinearLayout: onInterceptTouchEvent ACTION_MOVEMyButton: dispatchTouchEvent ACTION_MOVEMyButton: onTouch ACTION_MOVEMyButton: onTouchEvent ACTION_MOVEMyLinearLayout: dispatchTouchEvent ACTION_UPMyLinearLayout: onInterceptTouchEvent ACTION_UPMyButton: dispatchTouchEvent ACTION_UPMyButton: onTouch ACTION_UPMyButton: onTouchEvent ACTION_UP
事件流程
MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->MyButton的onTouch ->MyButton的onTouchEvent
总结:在view上触发事件,最先捕捉到事件的事view上viewgroup然后才是view自身.
源码分析
ViewGroup - dispatchTouchEven
1、ViewGroup - dispatchTouchEvent - ACTION_DOWN
首先是ViewGroup的dispatchTouchEvent方法:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!onFilterTouchEventForSecurity(ev)) { return false; } final int action = ev.getAction(); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + mScrollX; final float scrolledYFloat = yf + mScrollY; final Rect frame = mTempRect; boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (action == MotionEvent.ACTION_DOWN) { if (mMotionTarget != null) { // this is weird, we got a pen down, but we thought it was // already down! // XXX: We should probably send an ACTION_UP to the current // target. mMotionTarget = null; } // If we're disallowing intercept or if we're allowing and we didn't // intercept if (disallowIntercept || !onInterceptTouchEvent(ev)) { // reset this event's action (just to protect ourselves) ev.setAction(MotionEvent.ACTION_DOWN); // We know we want to dispatch the event down, find a child // who can handle it, start with the front-most child. final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.mLeft; final float yc = scrolledYFloat - child.mTop; ev.setLocation(xc, yc); child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; if (child.dispatchTouchEvent(ev)) { // Event handled, we have a target now. mMotionTarget = child; return true; } // The event didn't get handled, try the next view. // Don't reset the event's location, it's not // necessary here. } } } } } ....//other code omitted
ACTION_DOWN事件相关代码
进入ACTION_DOWN的处理
将mMotionTarget置为null
进行判断:if(disallowIntercept || !onInterceptTouchEvent(ev))
两种情况分析:
1.当前不允许拦截
2.当前允许拦截,但是不拦截即:disallowIntercept =false,但是onInterceptTouchEvent(ev)返回false ;
接着:遍历子view
进行判断当前的x,y坐标是否落在子View身上,如果在,47行,执行child.dispatchTouchEvent(ev),进入到view中dispatch
当child.dispatchTouchEvent(ev)返回true,则为mMotionTarget=child;然后return true
总结
1.ACTION_DOWN中,ViewGroup捕获到事件,然后判断是否拦截,如果没有拦截,找到包含x,y坐标的子view赋值给mMotionTarget,然后调用target.dispatchTouchEvent(ev);
2.ACTION_MOVE也是类似
3.ACTION_UP前面相同
总共:分发之前修改坐标系统,把当前x,y分别减去child.left和 child.top,然后传递给child.
拦截
ViewGroup的onInterceptTouchEvent方法:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: //如果你觉得需要拦截 return true ; case MotionEvent.ACTION_MOVE: //如果你觉得需要拦截 return true ; case MotionEvent.ACTION_UP: //如果你觉得需要拦截 return true ; } return false; }
默认不拦截,返回false;如果你需要拦截,只需要return true就行了.则该事件不会往子view传递.如果你在down,return true, 则down,move,up 子view都不会捕获; 如果你在move return true,则子view move up,都不会捕获事件.原因:当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ;
如何 不被拦截
如果viewgroup的onInterceptTouchEvent(ev) 当ACTION_MOVE return true,即拦截子view move和 up事件,如果子view,希望能够响应这两个事件?
requestDisallowInterceptTouchEvent 这个方法,用于设置是否允许拦截.
在子view 的dispatchTouchEvent中
@Override public boolean dispatchTouchEvent(MotionEvent event) { getParent().requestDisallowInterceptTouchEvent(true); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "dispatchTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "dispatchTouchEvent ACTION_UP"); break; default: break; } return super.dispatchTouchEvent(event); }
即使viewgroup,在MOVE return true,子view 仍然能捕捉move 和 up 事件.
总结
1.如果viewgroup找到了处理该事件的view,直接交给子view处理,自己onTouchEvent不会触发.
2.可以通过腹泻onInterceptTouchEvent( ) 方法,拦截子view,交给自己处理,会执行自己对应的onTouchEvent
3.子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止viewgroup对move和up进行拦截.
- viewGroup事件分发记录
- android 事件分发 ViewGroup
- ViewGroup的事件分发
- ViewGroup事件分发机制
- ViewGroup事件分发处理
- ViewGroup事件分发
- ViewGroup事件分发
- ViewGroup事件分发
- ViewGroup的事件分发
- 事件分发(ViewGroup)
- ViewGroup事件分发
- ViewGroup事件分发
- 事件分发机制---ViewGroup
- ViewGroup事件分发机制
- ViewGroup 事件分发
- ViewGroup的事件分发机制
- Android ViewGroup事件分发机制
- Android ViewGroup事件分发机制
- 详解5种跨域方式及其原理
- Https单向认证和双向认证
- 开创未来
- 原始粉丝积累秘籍【第三关】把你的资源,转化为粉丝
- OnCollisionEnter
- viewGroup事件分发记录
- #if #ifndef #if defined等
- 理解OpenGLSuperbible7-BasicFBO
- AXure 8.0实例——文本框:带图标文字提示
- cocos2dx DrawNode.drawSegment绘制出来的线粗细不一
- 继承,代码块,final,super第8天
- 说说JSON和JSONP,跨域解决问题
- Oracle 提高查询效率的34条方法
- linux实操常用命令总结