編輯:關於Android編程
public boolean dispatchTouchEvent(MotionEvent ev) { //驗證事件是否連續 if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } //這個變量用於記錄事件是否被處理完 boolean handled = false; //過濾掉一些不合法的事件:當前的View的窗口被遮擋了。 if (onFilterTouchEventForSecurity(ev)) { //如果事件發生的View在的窗口,沒有被遮擋 final int action = ev.getAction(); //重置前面為0 ,只留下後八位,用於判斷相等時候,可以提高性能。 final int actionMasked = action & MotionEvent.ACTION_MASK; //判斷是不是Down事件,如果是的話,就要做初始化操作 if (actionMasked == MotionEvent.ACTION_DOWN) { //如果是down事件,就要清空掉之前的狀態,比如,重置手勢判斷什麼的。 //比如,之前正在判斷是不是一個單點的滑動,但是第二個down來了,就表示,不可能是單點的滑動,要重新開始判斷觸摸的手勢 //清空掉mFirstTouchTarget // Throw away all previous state when starting a new touch gesture. // The framework may have dropped the up or cancel event for the previous gesture // due to an app switch, ANR, or some other state change. cancelAndClearTouchTargets(ev); resetTouchState(); } //檢查是否攔截事件 final boolean intercepted; //如果當前是Down事件,或者已經有處理Touch事件的目標了 if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { //判斷允不允許這個View攔截 //使用與運算作為判斷,可以讓我們在flag中,存儲好幾個標志 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; //如果說允許攔截事件 if (!disallowIntercept) { //確定是不是攔截了 intercepted = onInterceptTouchEvent(ev); //重新恢復Action,以免action在上面的步驟被人為地改變了 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. //如果說,事件已經初始化過了,並且沒有子View被分配處理,那麼就說明,這個ViewGroup已經攔截了這個事件 intercepted = true; } // Check for cancelation. //如果viewFlag被設置了PFLAG_CANCEL_NEXT_UP_EVENT ,那麼就表示,下一步應該是Cancel事件 //或者如果當前的Action為取消,那麼當前事件應該就是取消了。 final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL; // Update list of touch targets for pointer down, if needed. //如果需要(不是取消,也沒有被攔截)的話,那麼在觸摸down事件的時候更新觸摸目標列表 //split代表,當前的ViewGroup是不是支持分割MotionEvent到不同的View當中 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; //新的觸摸對象, TouchTarget newTouchTarget = null; //是否把事件分配給了新的觸摸 boolean alreadyDispatchedToNewTouchTarget = false; //事件不是取消事件,也沒有攔截那麼就要判斷 if (!canceled && !intercepted) { //如果是個全新的Down事件 //或者是有新的觸摸點 //或者是光標來回移動事件(不太明白什麼時候發生) if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { //這個事件的索引,也就是第幾個事件,如果是down事件就是0 final int actionIndex = ev.getActionIndex(); // always 0 for down //獲取分配的ID的bit數量 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) : TouchTarget.ALL_POINTER_IDS; // Clean up earlier touch targets for this pointer id in case they // have become out of sync. //清理之前觸摸這個指針標識,以防他們的目標變得不同步。 removePointersFromTouchTargets(idBitsToAssign); final int childrenCount = mChildrenCount; //如果新的觸摸對象為null(這個不是鐵定的嗎)並且當前ViewGroup有子元素 if (newTouchTarget == null && childrenCount != 0) { final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. //下面所做的工作,就是找到可以接收這個事件的子元素 final View[] children = mChildren; //是否使用自定義的順序來添加控件 final boolean customOrder = isChildrenDrawingOrderEnabled(); for (int i = childrenCount - 1; i >= 0; i--) { //如果是用了自定義的順序來添加控件,那麼繪制的View的順序和mChildren的順序是不一樣的 //所以要根據getChildDrawingOrder取出真正的繪制的View //自定義的繪制,可能第一個會畫到第三個,和第四個,第二個畫到第一個,這樣裡面的內容和Children是不一樣的 final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; final View child = children[childIndex]; //如果child不可以接收這個觸摸的事件,或者觸摸事件發生的位置不在這個View的范圍內 if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; } //獲取新的觸摸對象,如果當前的子View在之前的觸摸目標的列表當中就返回touchTarget //子View不在之前的觸摸目標列表那麼就返回null newTouchTarget = getTouchTarget(child); if (newTouchTarget != null) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the ones it is handling. //如果新的觸摸目標對象不為空,那麼就把這個觸摸的ID賦予它,這樣子, //這個觸摸的目標對象的id就含有了好幾個pointer的ID了 newTouchTarget.pointerIdBits |= idBitsToAssign; break; } //如果子View不在之前的觸摸目標列表中,先重置childView的標志,去除掉CACEL的標志 resetCancelNextUpFlag(child); //調用子View的dispatchTouchEvent,並且把pointer的id 賦予進去 //如果說,子View接收並且處理了這個事件,那麼就更新上一次觸摸事件的信息, //並且為創建一個新的觸摸目標對象,並且綁定這個子View和Pointer的ID if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. mLastTouchDownTime = ev.getDownTime(); mLastTouchDownIndex = childIndex; mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true; break; } } } //如果newTouchTarget為null,就代表,這個事件沒有找到子View去處理它, //那麼,如果之前已經有了觸摸對象(比如,我點了一張圖,另一個手指在外面圖的外面點下去) //那麼就把這個之前那個觸摸目標定為第一個觸摸對象,並且把這個觸摸(pointer)分配給最近添加的觸摸目標 if (newTouchTarget == null && mFirstTouchTarget != null) { // Did not find a child to receive the event. // Assign the pointer to 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 treat this as an ordinary view. //那麼就表示我們要自己在這個ViewGroup處理這個觸摸事件了 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; //遍歷TouchTargt樹.分發事件,如果我們已經分發給了新的TouchTarget那麼我們就不再分發給newTouchTarget while (target != null) { final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { //是否讓child取消處理事件,如果為true,就會分發給child一個ACTION_CANCEL事件 final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted; //派發事件 if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } //cancelChild也就是說,派發給了當前child一個ACTION_CANCEL事件, //那麼就移除這個child if (cancelChild) { //沒有父節點,也就是當前是第一個TouchTarget //那麼就把頭去掉 if (predecessor == null) { mFirstTouchTarget = next; } else { //把下一個賦予父節點的上一個,這樣當前節點就被丟棄了 predecessor.next = next; } //回收內存 target.recycle(); //把下一個賦予現在 target = next; //下面的兩行不執行了,因為我們已經做了鏈表的操作了。 //主要是我們不能執行predecessor=target,因為刪除本節點的話,父節點還是父節點 continue; } } //如果沒有刪除本節點,那麼下一輪父節點就是當前節點,下一個節點也是下一輪的當前節點 predecessor = target; target = next; } } // 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) { //如果是多點觸摸下的手指抬起事件,就要根據idBit從TouchTarget中移除掉對應的Pointer(觸摸點) 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游戲開發學習①彈跳小球實現方法。分享給大家供大家參考。具體如下:在學習了一點點Android之後,覺得有必要記錄下來,於是就開了這個新坑,慢慢
目前Android在全世界市場上大約有75%的占有率,國人Android手機的持有比例更甚,甚至達到90%以上。因此搞計算機的一聽說手機應用開發,一個個都像著了魔似的,既
前言別看本文看上去很簡單,實際在實驗過程中遇到了很多問題,比如andorid studio下ndk編譯報錯,而本文呈現給大家的都是最終可行的方法.所需資源bzip2 bs
在同組項目進行共享時,容易把本地的配置文件比如*.iml等文件上傳至共享服務器,這樣會對隊友造成巨大的麻煩,為了解決這個問題,可以使用下面方法解決,下面以上傳到服務器的a