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

來源:互聯網
上載者:User

焦點處理相關記錄以下所涉及的焦點部分,只是按鍵移動部分,不明確包含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;                    }                }                ...            }        }由此方法可以看出,最主要的兩個核心過程:12View 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.javapublic 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.javapublic 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.javapublic final View findNextFocus(ViewGroup root, View focused, int direction) {    return findNextFocus(root, focused, null, direction);} //FocusFinder.javaprivate 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.javaprivate 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.javaView 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.javaprivate 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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.