深入探索Android 中view的touch事件传递
来源:互联网 发布:数据恢复精灵下载 编辑:程序博客网 时间:2024/04/19 10:59
每个View的子类都具有下面三个方法:
一、这个方法用来分发TouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
//请求所有父控件及间接父控件不要拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
(1)如果返回true ,事件将会被终止。
(2)如果返回false,则交给上层view的onTouchEvent处理。
(3)返回super.dispatchTouchEvent(ev),才表明向下传递
二、这个方法用来拦截TouchEvent
@Override
publicboolean onInterceptTouchEvent(MotionEvent arg0) {
returnfalse;//false不拦截内层事件传递,true是拦截
}
1、返回 true,则表示将事件进行拦截,并将拦截到的事件交由他的 onTouchEvent 进行处理;
2、返回结果是false;则表示不对事件进行拦截,事件将传递给上层View的dispatchTouchEvent。
返回super.onInterceptTouchEvent(ev),事件默认不会被拦截,但内部会进行判断。
3)这个方法用来处理触摸事件(TouchEvent)
@Override
public booleanonTouchEvent(MotionEvent arg0) {
returntrue;//
}
如果onTouchEvent返回true,说明事件被该view处理了。不在向下传递(即不向上层view传递),如果该方法中什么都不操作,那么触摸后就真的什么都不做。
如果onTouchEvent返回false,事件将会继续向下传递,直到被处理。
如果返回super.onTouchEvent(ev)。默认继续向下传递
执行顺序:dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent
事件捕获机制:
1、当有监听事件时,首先由Activity的捕获到,进入事件分发处理流程。
2、如果事件分发返回系统默认的 super.dispatchTouchEvent(ev),事件将分发给本层的事件拦截onInterceptTouchEvent 方法进行处理。
如果事件分发返回 false,表明事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法
注意:Activity,没有事件拦截,将会把事件传递给该activity根布局容器的分发dispatchTouchEvent。
3、事件是从布局跟容器逐层向上传递的,直到事件被处理。
详细请看view层级结构图。
super.onTouchEvent(ev)源码
@Override
publicboolean onTouchEvent(MotionEvent ev) {
if (mFakeDragging) {
// A fake drag is in progress already, ignore this real one
// but still eat the touch events.
// (It is likely that the user is multi-touching the screen.)
return true;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN&& ev.getEdgeFlags() != 0) {
// Don't handle edge touches immediately -- they may actually belong toone of our
// descendants.
return false;
}
if (mAdapter == null || mAdapter.getCount() == 0) {
// Nothing to present or scroll; nothing to touch.
return false;
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
final int action = ev.getAction();
boolean needsInvalidate = false;
switch (action & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_DOWN: {
mScroller.abortAnimation();
mPopulatePending = false;
populate();
// Remember where the motionevent started
mLastMotionX = mInitialMotionX= ev.getX();
mLastMotionY = mInitialMotionY= ev.getY();
mActivePointerId =MotionEventCompat.getPointerId(ev, 0);
break;
}
case MotionEvent.ACTION_MOVE:
if (!mIsBeingDragged) {
final int pointerIndex= MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x= MotionEventCompat.getX(ev, pointerIndex);
final float xDiff= Math.abs(x - mLastMotionX);
final float y= MotionEventCompat.getY(ev, pointerIndex);
final float yDiff= Math.abs(y - mLastMotionY);
if (DEBUG)Log.v(TAG, "Moved x to " + x + "," + y+ " diff=" + xDiff + "," + yDiff);
if (xDiff >mTouchSlop && xDiff > yDiff) {
if (DEBUG)Log.v(TAG, "Starting drag!");
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
mLastMotionX = x -mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
mInitialMotionX- mTouchSlop;
mLastMotionY = y;
setScrollState(SCROLL_STATE_DRAGGING);
setScrollingCacheEnabled(true);
// Disallow ParentIntercept, just in case
ViewParent parent= getParent();
if (parent != null){
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
// Not else! Note thatmIsBeingDragged can be set above.
if (mIsBeingDragged) {
// Scroll to follow themotion event
final int activePointerIndex= MotionEventCompat.findPointerIndex(
ev,mActivePointerId);
final float x= MotionEventCompat.getX(ev, activePointerIndex);
needsInvalidate |=performDrag(x);
}
break;
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
finalVelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity= (int) VelocityTrackerCompat.getXVelocity(
velocityTracker,mActivePointerId);
mPopulatePending = true;
final int width= getClientWidth();
final int scrollX= getScrollX();
final ItemInfo ii= infoForCurrentScrollPosition();
final int currentPage= ii.position;
final float pageOffset= (((float) scrollX / width) - ii.offset) / ii.widthFactor;
final int activePointerIndex=
MotionEventCompat.findPointerIndex(ev,mActivePointerId);
final float x= MotionEventCompat.getX(ev, activePointerIndex);
final int totalDelta= (int) (x - mInitialMotionX);
int nextPage= determineTargetPage(currentPage, pageOffset, initialVelocity,
totalDelta);
setCurrentItemInternal(nextPage,true, true, initialVelocity);
mActivePointerId = INVALID_POINTER;
endDrag();
needsInvalidate =mLeftEdge.onRelease() | mRightEdge.onRelease();
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged) {
scrollToItem(mCurItem, true,0, false);
mActivePointerId = INVALID_POINTER;
endDrag();
needsInvalidate =mLeftEdge.onRelease() | mRightEdge.onRelease();
}
break;
case MotionEventCompat.ACTION_POINTER_DOWN: {
final int index= MotionEventCompat.getActionIndex(ev);
final float x= MotionEventCompat.getX(ev, index);
mLastMotionX = x;
mActivePointerId =MotionEventCompat.getPointerId(ev, index);
break;
}
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
mLastMotionX =MotionEventCompat.getX(ev,
MotionEventCompat.findPointerIndex(ev,mActivePointerId));
break;
}
if (needsInvalidate) {
ViewCompat.postInvalidateOnAnimation(this);
}
return true;
}
super.onInterceptTouchEvent(ev)源码
@Override
public boolean onInterceptTouchEvent(MotionEventev) {
/*
* This method JUST determines whetherwe want to intercept the motion.
* If we return true, onMotionEventwill be called and we do the actual
* scrolling there.
*/
final int action =ev.getAction() & MotionEventCompat.ACTION_MASK;
// Always take care of the touchgesture being complete.
if (action == MotionEvent.ACTION_CANCEL|| action == MotionEvent.ACTION_UP) {
// Release the drag.
if (DEBUG)Log.v(TAG, "Intercept done!");
mIsBeingDragged = false;
mIsUnableToDrag = false;
mActivePointerId = INVALID_POINTER;
if (mVelocityTracker != null){
mVelocityTracker.recycle();
mVelocityTracker = null;
}
return false;
}
// Nothing more to do here if we havedecided whether or not we
// are dragging.
if (action != MotionEvent.ACTION_DOWN){
if (mIsBeingDragged) {
if (DEBUG)Log.v(TAG, "Intercept returning true!");
return true;
}
if (mIsUnableToDrag) {
if (DEBUG)Log.v(TAG, "Intercept returning false!");
return false;
}
}
switch (action) {
case MotionEvent.ACTION_MOVE:{
/*
* mIsBeingDragged == false,otherwise the shortcut would have caught it. Check
* whether the user has movedfar enough from his original down touch.
*/
/*
* Locally do absolute value.mLastMotionY is set to the y value
* of the down event.
*/
final int activePointerId= mActivePointerId;
if (activePointerId == INVALID_POINTER){
// If we don't have a validid, the touch down wasn't on content.
break;
}
final int pointerIndex= MotionEventCompat.findPointerIndex(ev, activePointerId);
final float x= MotionEventCompat.getX(ev, pointerIndex);
final float dx= x - mLastMotionX;
final float xDiff= Math.abs(dx);
final float y= MotionEventCompat.getY(ev, pointerIndex);
final float yDiff= Math.abs(y - mInitialMotionY);
if (DEBUG)Log.v(TAG, "Moved x to " + x + "," + y+ " diff=" + xDiff + "," + yDiff);
if (dx != 0 &&!isGutterDrag(mLastMotionX, dx) &&
canScroll(this, false,(int) dx, (int) x, (int) y)) {
// Nested view hasscrollable area under this point. Let it be handled there.
mLastMotionX = x;
mLastMotionY = y;
mIsUnableToDrag = true;
return false;
}
if (xDiff >mTouchSlop && xDiff * 0.5f > yDiff) {
if (DEBUG)Log.v(TAG, "Starting drag!");
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
mLastMotionX = dx > 0 ?mInitialMotionX + mTouchSlop :
mInitialMotionX -mTouchSlop;
mLastMotionY = y;
setScrollingCacheEnabled(true);
} else if (yDiff> mTouchSlop) {
// The finger has movedenough in the vertical
// direction to be countedas a drag... abort
// any attempt to draghorizontally, to work correctly
// with children that havescrolling containers.
if (DEBUG) Log.v(TAG,"Starting unable to drag!");
mIsUnableToDrag = true;
}
if (mIsBeingDragged) {
// Scroll to follow themotion event
if (performDrag(x)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
break;
}
case MotionEvent.ACTION_DOWN:{
/*
* Remember location of downtouch.
* ACTION_DOWN always refers topointer index 0.
*/
mLastMotionX = mInitialMotionX= ev.getX();
mLastMotionY = mInitialMotionY= ev.getY();
mActivePointerId = MotionEventCompat.getPointerId(ev,0);
mIsUnableToDrag = false;
mScroller.computeScrollOffset();
if (mScrollState == SCROLL_STATE_SETTLING&&
Math.abs(mScroller.getFinalX()- mScroller.getCurrX()) > mCloseEnough) {
// Let the user 'catch' thepager as it animates.
mScroller.abortAnimation();
mPopulatePending = false;
populate();
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
} else {
completeScroll(false);
mIsBeingDragged = false;
}
if (DEBUG)Log.v(TAG, "Down at " + mLastMotionX +"," + mLastMotionY
+ "mIsBeingDragged=" + mIsBeingDragged
+"mIsUnableToDrag=" + mIsUnableToDrag);
break;
}
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
if (mVelocityTracker == null){
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
/*
* The only time we want to interceptmotion events is if we are in the
* drag mode.
*/
return mIsBeingDragged;
}
super.dispatchTouchEvent(ev)源码
@Override
public boolean dispatchTouchEvent(MotionEventev) {
if(mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
// If the event targets theaccessibility focused view and this is it, start
// normal event dispatch. Maybe adescendant is what will handle the click.
if(ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()){
ev.setTargetAccessibilityFocus(false);
}
boolean handled = false;
if(onFilterTouchEventForSecurity(ev)) {
final int action= ev.getAction();
final int actionMasked= action & MotionEvent.ACTION_MASK;
// Handle an initial down.
if (actionMasked ==MotionEvent.ACTION_DOWN) {
// Throw away all previousstate when starting a new touch gesture.
// The framework may havedropped the up or cancel event for the previous gesture
// due to an app switch, ANR,or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
// Check for interception.
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); // restoreaction in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targetsand this action is not an initial down
// so this view group continuesto intercept touches.
intercepted = true;
}
// If intercepted, start normalevent dispatch. Also if there is already
// a view that is handling the gesture,do normal event dispatch.
if (intercepted ||mFirstTouchTarget != null) {
ev.setTargetAccessibilityFocus(false);
}
// Check for cancelation.
final boolean canceled= resetCancelNextUpFlag(this)
|| actionMasked ==MotionEvent.ACTION_CANCEL;
// Update list of touch targets forpointer down, if needed.
final boolean split= (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
TouchTarget newTouchTarget =null;
boolean alreadyDispatchedToNewTouchTarget= false;
if (!canceled &&!intercepted) {
// If the event is targetingaccessiiblity focus we give it to the
// view that has accessibilityfocus and if it does not handle it
// we clear the flag anddispatch the event to all children as usual.
// We are looking up theaccessibility focused host to avoid keeping
// state since these events arevery rare.
View childWithAccessibilityFocus= ev.isTargetAccessibilityFocus()
?findChildWithAccessibilityFocus() : null;
if (actionMasked ==MotionEvent.ACTION_DOWN
|| (split &&actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked ==MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex= ev.getActionIndex(); // always 0 for down
final int idBitsToAssign= split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touchtargets for this pointer id in case they
// have become out of sync.
removePointersFromTouchTargets(idBitsToAssign);
final int childrenCount= mChildrenCount;
if (newTouchTarget== null && childrenCount != 0) {
final floatx = ev.getX(actionIndex);
final floaty = ev.getY(actionIndex);
// Find a child thatcan receive the event.
// Scan children fromfront to back.
finalArrayList<View> preorderedList = buildOrderedChildList();
final booleancustomOrder = preorderedList ==null
&&isChildrenDrawingOrderEnabled();
final View[] children= mChildren;
for (int i= childrenCount - 1; i >= 0; i--) {
final intchildIndex = customOrder
?getChildDrawingOrder(childrenCount, i) : i;
final View child= (preorderedList ==null)
?children[childIndex] : preorderedList.get(childIndex);
// If there is aview that has accessibility focus we want it
// to get the eventfirst and if not handled we will perform a
// normal dispatch.We may do a double iteration but this is
// safer given thetimeframe.
if(childWithAccessibilityFocus !=null) {
if(childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i =childrenCount - 1;
}
if (!canViewReceivePointerEvents(child)
||!isTransformedTouchPointInView(x, y, child,null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
newTouchTarget =getTouchTarget(child);
if(newTouchTarget != null) {
// Child isalready receiving touch within its bounds.
// Give it thenew pointer in addition to the ones it is handling.
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
if(dispatchTransformedTouchEvent(ev,false, child, idBitsToAssign)) {
// Child wantsto receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if(preorderedList != null) {
//childIndex points into presorted list, find original index
for(int j = 0; j < childrenCount; j++) {
if(children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX= ev.getX();
mLastTouchDownY= ev.getY();
newTouchTarget= addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget= true;
break;
}
// Theaccessibility focus didn't handle the event, so clear
// the flag and doa normal dispatch to all children.
ev.setTargetAccessibilityFocus(false);
}
if(preorderedList != null) preorderedList.clear();
}
if (newTouchTarget== null && mFirstTouchTarget !=null) {
// Did not find a childto receive the event.
// Assign the pointerto the least recently added target.
newTouchTarget =mFirstTouchTarget;
while (newTouchTarget.next != null){
newTouchTarget =newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
// Dispatch to touch targets.
if (mFirstTouchTarget == null){
// No touch targets so treatthis as an ordinary view.
handled =dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
// Dispatch to touch targets,excluding the new touch target if we already
// dispatched to it. Cancel touch targets if necessary.
TouchTarget predecessor= null;
TouchTarget target =mFirstTouchTarget;
while (target != null){
final TouchTarget next= target.next;
if(alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final booleancancelChild = 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;
}
}
predecessor = target;
target = next;
}
}
// Update list of touch targets forpointer 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;
}
布局截图和层级截图:
- 深入探索Android 中view的touch事件传递
- Android中view的Touch事件传递顺序
- Android 之在View以及ViewGroup中Touch事件传递
- Android中Touch事件的传递过程
- Android中view的Touch事件
- Android touch事件传递及View的绘制流程
- Android View touch事件传递方式规律
- Android View Touch事件传递机制
- 深入Android Touch事件传递机制
- android Touch事件传递机制深入剖析
- 深入探索 ViewGroup 的事件传递机制
- Android中Touch事件传递机制解析
- android View touch的传递流程
- android touch事件传递
- Android Touch事件传递
- Android touch事件传递
- Android touch 事件传递
- Android Touch事件传递
- Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 无效字符
- 优雅编程之这样简化表达式,你就“正常”了(二十三)
- APACHE FALCON CLI
- 02.Spring Ioc 容器 - 创建
- JS 模块模式
- 深入探索Android 中view的touch事件传递
- Linux下项目初次同步Github的步骤
- 优雅编程之这样简化函数,你就“正常”了(二十四)
- 搭建Dubbo+Myeclipse2015+Maven3.3.1的过程遇到问题集锦
- 顺丰测评
- linux进程控制
- leetcode 算法网址
- Mybatis学习中遇到的错误java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (ut
- Java之 无符号类型是怎么回事