導航:首頁 > 操作系統 > android兩個焦點

android兩個焦點

發布時間:2025-08-30 19:04:19

android TV 焦點原理源碼解析

相信很多剛接觸AndroidTV開發的開發者,都會被各種焦點問題給折磨的不行。不管是學技術還是學習其他知識,都要學習和理解其中原理,碰到問題我們才能得心應手。下面就來探一探Android的焦點分發的過程。

Android焦點事件的分發是從ViewRootImpl的processKeyEvent開始的,源碼如下:

源碼比較長,下面我就慢慢來講解一下具體的每一個細節。

dispatchKeyEvent方法返回true代表焦點事件被消費了。

ViewGroup的dispatchKeyEvent()方法的源碼如下:

(2)ViewGroup的dispatchKeyEvent執行流程

(3)下面再來瞧瞧view的dispatchKeyEvent方法的具體的執行過程

驚奇的發現執行了onKeyListener中的onKey方法,如果onKey方法返回true,那麼dispatchKeyEvent方法也會返回true

可以得出結論:如果想要修改ViewGroup焦點事件的分發,可以這么干:

注意:實際開發中,理論上所有焦點問題都可以通過給dispatchKeyEvent方法增加監聽來來攔截來控制。

(1)dispatchKeyEvent方法返回false後,先得到按鍵的方向direction值,這個值是一個int類型參數。這個direction值是後面來進行焦點查找的。

(2)接著會調用DecorView的findFocus()方法一層一層往下查找已經獲取焦點的子View。
ViewGroup的findFocus方法如下:

View的findFocus方法

說明:判斷view是否獲取焦點的isFocused()方法, (mPrivateFlags & PFLAG_FOCUSED) != 0 和view 的isFocused()方法是一致的。

其中isFocused()方法的作用是判斷view是否已經獲取焦點,如果viewGroup已經獲取到了焦點,那麼返回本身即可,否則通過mFocused的findFocus()方法來找焦點。mFocused其實就是ViewGroup中獲取焦點的子view,如果mView不是ViewGourp的話,findFocus其實就是判斷本身是否已經獲取焦點,如果已經獲取焦點了,返回本身。

(3)回到processKeyEvent方法中,如果findFocus方法返回的mFocused不為空,說明找到了當前獲取焦點的view(mFocused),接著focusSearch會把direction(遙控器按鍵按下的方向)作為參數,找到特定方向下一個將要獲取焦點的view,最後如果該view不為空,那麼就讓該view獲取焦點。

(4)focusSearch方法的具體實現。

focusSearch方法的源碼如下:

可以看出focusSearch其實是一層一層地網上調用父View的focusSearch方法,直到當前view是根布局(isRootNamespace()方法),通過注釋可以知道focusSearch最終會調用DecorView的focusSearch方法。而DecorView的focusSearch方法找到的焦點view是通過FocusFinder來找到的。

(5)FocusFinder是什麼?

它其實是一個實現 根據給定的按鍵方向,通過當前的獲取焦點的View,查找下一個獲取焦點的view這樣演算法的類。焦點沒有被攔截的情況下,Android框架焦點的查找最終都是通過FocusFinder類來實現的。

(6)FocusFinder是如何通過findNextFocus方法尋找焦點的。

下面就來看看FocusFinder類是如何通過findNextFocus來找焦點的。一層一層往下看,後面會執行findNextUserSpecifiedFocus()方法,這個方法會執行focused(即當前獲取焦點的View)的findUserSetNextFocus方法,如果該方法返回的View不為空,且isFocusable = true && isInTouchMode() = true的話,FocusFinder找到的焦點就是findNextUserSpecifiedFocus()返回的View。

(7)findNextFocus會優先根據XML里設置的下一個將獲取焦點的View ID值來尋找將要獲取焦點的View。

看看View的findUserSetNextFocus方法內部都幹了些什麼,OMG不就是通過我們xml布局裡設置的nextFocusLeft,nextFocusRight的viewId來找焦點嗎,如果按下Left鍵,那麼便會通過nextFocusLeft值里的View Id值去找下一個獲取焦點的View。

可以得出以下結論:

1. 如果一個View在XML布局中設置了focusable = true && isInTouchMode = true,那麼這個View會優先獲取焦點。

2. 通過設置nextFocusLeft,nextFocusRight,nextFocusUp,nextFocusDown值可以控制View的下一個焦點。

Android焦點的原理實現就這些。總結一下:

為了方便同志們學習,我這做了張導圖,方便大家理解~

② 怎麼讓android 頁面失去焦點

在網上找了好久,有點監聽軟鍵盤事件,有點調用 clearFouse()方法,但是測試了都沒有!xml中也找不到相應的屬性可以關閉這個默認行為

1 解決之道:在EditText的父級控制項中找一個,設置成

Android:focusable="true"
android:focusableInTouchMode="true"

這樣,就把EditText默認的行為截斷了!

<LinearLayout
style="@style/FillWrapWidgetStyle"
android:orientation="vertical"
android:background="@color/black"
android:gravity="center_horizontal"

android:focusable="true"
android:focusableInTouchMode="true"
>
<ImageView
android:id="@+id/logo"
style="@style/WrapContentWidgetStyle"
android:background="@drawable/dream_dictionary_logo"
/>
<RelativeLayout
style="@style/FillWrapWidgetStyle"
android:background="@drawable/searchbar_bg"
android:gravity="center_vertical"
>
<EditText
android:id="@+id/searchEditText"
style="@style/WrapContentWidgetStyle"
android:background="@null"
android:hint="Search"
android:layout_marginLeft="40dp"
android:singleLine="true"
/>

</RelativeLayout>

</LinearLayout>


2 還有一個方法也可以非常簡單的實現這個功能:

EditText對象的clearFocus();

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editMsgView.getWindowToken(), 0);(關閉軟鍵盤。。。)

3更多問題解決辦法請參考android學習手冊,例子、源碼、文檔全部搞定,採用androidstudo的目錄結構,360手機助手中下載。下面是截圖。

③ android 中如何設置焦點的位置。

默認從上倒下 從左到右第一個可以輸入的控制項作為焦點,如果不想默認可以指定某個view或得焦點

④ Android移動應用中的焦點分析

簡單一點理解,在移動應用中,焦點就是當前正在處理事件的位置。在手機應用中,最有可能用到焦點的就是EditText,如果同一個界面中有多個EditText,通常情況下同一時間只有一個能夠輸入內容,此時,這個EditText就獲取了焦點。

在Android中,對焦點的設置分為兩種情況,TouchMode和非TouchMode。現在的手機基本都是觸摸屏,我們用手指觸摸屏幕來操作Android應用時,處於TouchMode。除了TouchMode之外,還有非TouchMode,利用外接設備來操作早衫應用。比如鍵盤。使用Genymotion模擬器的時候,一個陸兄腔界面上有多個控制項時,可以用電腦tab鍵來進行移動,被選中的控制項會高亮顯示,這時候就是非TouchMode,被選中的控制項獲得了焦點。

在手機應用中,用到焦點的時候並不多,但是TV應用中,需要用遙控器來操作選中控制項,這時候就需要對焦點進行處理了。關於焦點,常用方法如下:

在View類中, isFocusable() 和 isFocusableInTouchMode() 獲取到的結果都是false,也就是說,直接繼承自View的控制項是不能獲取焦點的。我們常用控制項中對這兩個方法進行了改寫,比如EditText,這兩個方法都是true,而Button則只有 isFocusable() 返回true。這也就是為什麼我們用tab鍵選取Button的時候能夠高亮顯示,而滑鼠點擊(模擬觸控)的時候不能高亮顯示的原因了。如果想在點擊的時候也能高亮顯示Button,需要手動設置 setFocusableInTouchMode(true) ,就可以了。

如果想對控制項的焦點狀態進行監聽,需要設置 setOnFocusChangeListener() ,只要控制項的焦點狀態發生變化(獲得或者失去焦點),都會調用 onFocusChange 方法

關於焦點的移動,默認的演算法會尋找指定方向上最近的可以獲取焦點的元素(非TouchMode)。另外在創建控制項的時候,也可以指定尋找焦點的方向,設置nextFocusDown、nextFocusLeft、nextFocusRight 和 nextFocusUp的值為指定元素就可以了。看以下例子:

這里指定了上面的button向上尋找焦點時,下一個元素是id為bottom的元素,也就是說,上面的Button在獲取了焦點之後,繼續按向上鍵,系統會將焦點移動到id為bottom的元素上,而不是繼續向上。

在開發手機應用的過程中,對焦點的處理並不多,它與事件是兩個不同的體系,通常情況下焦點和事件是相互獨立並不沖突。但是在Button的點擊事件中會有一點問題。如果我們隊一個button設置了 setFocusableInTouchMode(true) ,使他可以獲取焦點,那麼我們點擊這個button的時候,第一次點擊並不會執行 onClick() 方法,而是執行 onFocusChange() 。第二次點擊的時候才會執行 onClick() 方法。看起來好像 onFocusChange() 消耗了點擊事件,實際上並不是的。

這個問題我們看一下源碼就清楚了:

onClick() 方法是在onTouchEvent的ACTION_UP里調用的,看一下View的onTouchEvent方法:

可以看到,只有當focusTaken為false的時候才會執行onClick,focusTaken的值默認是false的,但是在 isFocusable() && isFocusableInTouchMode() && !isFocused() 為true的時候,會去 requestFocus 獲取焦點,並將值賦給focusTaken。

關鍵在於 isFocused() ,如果當前Button沒塵碼有獲取焦點, isFocused() 返回false, !isFocused() 值為ture,Button就會去獲取焦點,從而導致 focusTaken 為true, onClick 方法就不會執行了,只有Button已經獲取了焦點的時候才會執行onClick方法。

閱讀全文

與android兩個焦點相關的資料

熱點內容
怎麼把電子版投標報價加密 瀏覽:29
電腦安全編譯器 瀏覽:364
在伺服器里如何調創造 瀏覽:835
知雲登錄為什麼找不到伺服器 瀏覽:815
python切片位置 瀏覽:374
平板加密視頻怎麼播放 瀏覽:377
程序員上下班不帶電腦 瀏覽:835
androidrsa文件 瀏覽:64
linuxlvds 瀏覽:103
程序員選擇職場 瀏覽:345
累加C語言演算法 瀏覽:948
足浴店用什麼app招人 瀏覽:191
php調用thrift 瀏覽:191
java精度丟失 瀏覽:903
地梁承台相交處箍筋加密 瀏覽:95
程序員繪本 瀏覽:647
php線程安全版 瀏覽:407
lilolinux 瀏覽:111
proteus51編譯工具 瀏覽:309
黑馬程序員c語言基礎函數 瀏覽:839