Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android學習筆記]理解焦點處理原理的相關記錄

[Android學習筆記]理解焦點處理原理的相關記錄

編輯:關於Android編程

焦點處理相關記錄 以下所涉及的焦點部分,只是按鍵移動部分,不明確包含Touch Focus部分   需解決問題 控件的下一個焦點是哪?   分析思路 當用戶通過按鍵(遙控器等)觸發焦點切換時,事件指令會通過底層進行一系列處理。 在ViewRootImpl.java中有一個方法,deliverKeyEventPostIme(...),因為涉及到底層代碼,所以沒有詳細的跟蹤分析此方法的調用邏輯,根據網上的資料,按鍵相關的處理會經過此方法。     private void deliverKeyEventPostIme(QueuedInputEvent q) {     ...     // Handle automatic focus changes.     if (event.getAction() == KeyEvent.ACTION_DOWN) {         int direction = 0;         switch (event.getKeyCode()) {             case KeyEvent.KEYCODE_DPAD_LEFT:                 if (event.hasNoModifiers()) {                     direction = View.FOCUS_LEFT;                 }                 break;             case KeyEvent.KEYCODE_DPAD_RIGHT:                 if (event.hasNoModifiers()) {                     direction = View.FOCUS_RIGHT;                 }                 break;             ...         }         if (direction != 0) {             View focused = mView.findFocus();             if (focused != null) {                 View v = focused.focusSearch(direction);                 if (v != null && v != focused) {                    .....                     if (v.requestFocus(direction, mTempRect)) {                         ...finishInputEvent(q, true);                         return;                     }                 }                 ...             }         } 由此方法可以看出,最主要的兩個核心過程: 1 2 View v = focused.focusSearch(direction); v.requestFocus(direction, mTempRect) 接下來詳細的分析下,看看過程中進行了什麼操作 具體分析 在具體分析前,首先我們先明確下相關變量的定義   View mView : 主體View[DecorView]     //一般把主View“DecorView”添加到WindowManagerImpl中(通過addView) //WindowManagerImpl.java     private void addView(View view...) {         ViewRootImpl root;         root = new ViewRootImpl(view.getContext());         ...         root.setView(view, wparams, panelParentView);         ...     }<br> //ViewRootImpl.java public void setView(View view....) {     synchronized (this) {         if (mView == null) {             mView = view;             ...         }     ...     } } 所以mView是一個DecorView類型的變量. View focused :         View focused = mView.findFocus();<br>     //PhoneWindow.java     private final class DecorView extends FrameLayout implements RootVie.... {         ...     }<br>     //FrameLayout.java     public class FrameLayout extends ViewGroup {         ...     }<br>     //ViewGroup.java     //mFocused記錄的是當前被焦點選中的view     @Override     public View findFocus() {     if (DBG) {         System.out.println("Find focus in " + this + ": flags="                 + isFocused() + ", child=" + mFocused);     }     if (isFocused()) {         return this;     }     if (mFocused != null) {         return mFocused.findFocus();     }     return null; } 所以最終得到的focused為當前頁面中得到焦點的view. 在明確的相關變量後,我們開始View v = focused.focusSearch(direction)的具體分析.     //View.java public View focusSearch(int direction) { //如果存在父控件,則執行父控件的focusSearch方法    if (mParent != null) {          return mParent.focusSearch(this, direction);      } else {          return null;      }  }  //ViewGroup.java  public View focusSearch(View focused, int direction) {      //判斷是否為頂層布局,若是則執行對應方法,若不是則繼續向上尋找,說明會從內到外的一層層進行判斷,直到最外層的布局為止      if (isRootNamespace()) {          return FocusFinder.getInstance().findNextFocus(this, focused, direction);      } else if (mParent != null) {          return mParent.focusSearch(focused, direction);      }      return null;  } 說明在這個過程中,其實是從裡層開始一直遍歷到最外層布局,然後在最外層布局將處理交給了FocusFinder中的方法.     FocusFinder.getInstance().findNextFocus(this, focused, direction); 那我們來看看此方法具體做了什麼操作   //FocusFinder.java public final View findNextFocus(ViewGroup root, View focused, int direction) {     return findNextFocus(root, focused, null, direction); }   //FocusFinder.java private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {     View next = null;     if (focused != null) {         next = findNextUserSpecifiedFocus(root, focused, direction);     }     if (next != null) {         return next;     }     ArrayList<View> focusables = mTempList;     try {         focusables.clear();         root.addFocusables(focusables, direction);         if (!focusables.isEmpty()) {             next = findNextFocus(root, focused, focusedRect, direction, focusables);         }     } finally {         focusables.clear();     }     return next; } 發現在findNextFocus的執行過程的開始,先執行了findNextUserSpecifiedFocus(...)方法,由代碼可以看出,此方法先去判斷特定Id值是否存在,若存在則查詢出Id對應的view.其實這些Id就是xml裡通過android:nextFocusUp="..."等或者代碼特別指定的焦點順序.所以在此過程先判斷,若存在,說明下個焦點已經找到,直接返回.   //FocusFinder.java private View findNextUserSpecifiedFocus(ViewGroup root, View focused, int direction) {     // check for user specified next focus     View userSetNextFocus = focused.findUserSetNextFocus(root, direction);     if (userSetNextFocus != null && userSetNextFocus.isFocusable()             && (!userSetNextFocus.isInTouchMode()                     || userSetNextFocus.isFocusableInTouchMode())) {         return userSetNextFocus;     }     return null; }<br> //View.java View findUserSetNextFocus(View root, int direction) {     switch (direction) {         case FOCUS_LEFT:             if (mNextFocusLeftId == View.NO_ID) return null;             return findViewInsideOutShouldExist(root, mNextFocusLeftId);         case FOCUS_RIGHT:             if (mNextFocusRightId == View.NO_ID) return null;             return findViewInsideOutShouldExist(root, mNextFocusRightId);         case FOCUS_UP:             if (mNextFocusUpId == View.NO_ID) return null;             return findViewInsideOutShouldExist(root, mNextFocusUpId);         case FOCUS_DOWN:             if (mNextFocusDownId == View.NO_ID) return null;             return findViewInsideOutShouldExist(root, mNextFocusDownId);         case FOCUS_FORWARD:             if (mNextFocusForwardId == View.NO_ID) return null;             return findViewInsideOutShouldExist(root, mNextFocusForwardId);         case FOCUS_BACKWARD: {             if (mID == View.NO_ID) return null;             final int id = mID;             return root.findViewByPredicateInsideOut(this, new Predicate<View>() {                 @Override                 public boolean apply(View t) {                     return t.mNextFocusForwardId == id;                 }             });         }     }     return null; } 如果上面過程沒有查詢到,則會執行到findNextFocus(...)方法.在這個方法中,先通過offsetDescendantRectToMyCoords(...)方法獲得焦點控件的位置矩陣.然後通過比較得到下一個焦點的控件。具體的比較規則可以查看findNextFocusInRelativeDirection(...)方法與findNextFocusInAbsoluteDirection(...)方法.   //FocusFinder.java private View findNextFocus(ViewGroup root, View focused, Rect focusedRect,         int direction, ArrayList<View> focusables) {     if (focused != null) {         if (focusedRect == null) {             focusedRect = mFocusedRect;         }         // fill in interesting rect from focused         focused.getFocusedRect(focusedRect);         root.offsetDescendantRectToMyCoords(focused, focusedRect);     } else {         if (focusedRect == null) {             focusedRect = mFocusedRect;             // make up a rect at top left or bottom right of root             switch (direction) {                 case View.FOCUS_RIGHT:                 case View.FOCUS_DOWN:                     setFocusTopLeft(root, focusedRect);                     break;                 case View.FOCUS_FORWARD:                     if (root.isLayoutRtl()) {                         setFocusBottomRight(root, focusedRect);                     } else {                         setFocusTopLeft(root, focusedRect);                     }                     break;                 case View.FOCUS_LEFT:                 case View.FOCUS_UP:                     setFocusBottomRight(root, focusedRect);                     break;                 case View.FOCUS_BACKWARD:                     if (root.isLayoutRtl()) {                         setFocusTopLeft(root, focusedRect);                     } else {                         setFocusBottomRight(root, focusedRect);                     break;                 }             }         }     }     switch (direction) {         case View.FOCUS_FORWARD:         case View.FOCUS_BACKWARD:             return findNextFocusInRelativeDirection(focusables, root, focused, focusedRect,                     direction);         case View.FOCUS_UP:         case View.FOCUS_DOWN:         case View.FOCUS_LEFT:         case View.FOCUS_RIGHT:             return findNextFocusInAbsoluteDirection(focusables, root, focused,                     focusedRect, direction);         default:             throw new IllegalArgumentException("Unknown direction: " + direction);     } } 結論 查找焦點的過程,主要是從View的focusSearch(...)方法開始,從當前焦點開始逐層往外,最終在最外層布局執行FocusFinder中的核心方法來獲得下個焦點所在的視圖view.   如果需要指定跳轉,可以在逐層focusSearch(...)的時候,返回特定的view
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved