什么是焦點
簡單一點理解,在移動應(yīng)用中侄旬,焦點就是當(dāng)前正在處理事件的位置望抽。在手機(jī)應(yīng)用中加矛,最有可能用到焦點的就是EditText,如果同一個界面中有多個EditText煤篙,通常情況下同一時間只有一個能夠輸入內(nèi)容斟览,此時,這個EditText就獲取了焦點辑奈。
在Android中苛茂,對焦點的設(shè)置分為兩種情況,TouchMode和非TouchMode○埃現(xiàn)在的手機(jī)基本都是觸摸屏妓羊,我們用手指觸摸屏幕來操作Android應(yīng)用時,處于TouchMode稍计。除了TouchMode之外躁绸,還有非TouchMode,利用外接設(shè)備來操作應(yīng)用臣嚣。比如鍵盤净刮。使用Genymotion模擬器的時候,一個界面上有多個控件時茧球,可以用電腦tab鍵來進(jìn)行移動庭瑰,被選中的控件會高亮顯示,這時候就是非TouchMode抢埋,被選中的控件獲得了焦點弹灭。
焦點的使用
在手機(jī)應(yīng)用中,用到焦點的時候并不多揪垄,但是TV應(yīng)用中穷吮,需要用遙控器來操作選中控件,這時候就需要對焦點進(jìn)行處理了饥努。關(guān)于焦點捡鱼,常用方法如下:
isFocusableInTouchMode() //在TouchMode中是否能夠獲取焦點
isFocusable()//是否能獲取焦點
setFocusableInTouchMode(boolean) //設(shè)置在TouchMode中是否能夠獲取焦點
setFocusable(boolean) //設(shè)置是否能獲取焦點
setOnFocusChangeListener()//設(shè)置焦點變化監(jiān)聽
OnFocusChangeListener()
requestFocus() //獲取焦點
isFocused()//是否獲取到焦點
在View類中,isFocusable()
和isFocusableInTouchMode()
獲取到的結(jié)果都是false酷愧,也就是說驾诈,直接繼承自View的控件是不能獲取焦點的缠诅。我們常用控件中對這兩個方法進(jìn)行了改寫,比如EditText乍迄,這兩個方法都是true管引,而Button則只有isFocusable()
返回true。這也就是為什么我們用tab鍵選取Button的時候能夠高亮顯示闯两,而鼠標(biāo)點擊(模擬觸控)的時候不能高亮顯示的原因了褥伴。如果想在點擊的時候也能高亮顯示Button,需要手動設(shè)置setFocusableInTouchMode(true)
漾狼,就可以了重慢。
如果想對控件的焦點狀態(tài)進(jìn)行監(jiān)聽,需要設(shè)置setOnFocusChangeListener()
逊躁,只要控件的焦點狀態(tài)發(fā)生變化(獲得或者失去焦點)似踱,都會調(diào)用onFocusChange
方法
關(guān)于焦點的移動,默認(rèn)的算法會尋找指定方向上最近的可以獲取焦點的元素(非TouchMode)志衣。另外在創(chuàng)建控件的時候屯援,也可以指定尋找焦點的方向,設(shè)置nextFocusDown念脯、nextFocusLeft狞洋、nextFocusRight 和 nextFocusUp的值為指定元素就可以了÷痰辏看以下例子:
<LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
... />
<Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
</LinearLayout>
這里指定了上面的button向上尋找焦點時吉懊,下一個元素是id為bottom的元素,也就是說假勿,上面的Button在獲取了焦點之后借嗽,繼續(xù)按向上鍵,系統(tǒng)會將焦點移動到id為bottom的元素上转培,而不是繼續(xù)向上恶导。
焦點與事件
在開發(fā)手機(jī)應(yīng)用的過程中,對焦點的處理并不多浸须,它與事件是兩個不同的體系惨寿,通常情況下焦點和事件是相互獨(dú)立并不沖突。但是在Button的點擊事件中會有一點問題删窒。如果我們隊一個button設(shè)置了setFocusableInTouchMode(true)
裂垦,使他可以獲取焦點,那么我們點擊這個button的時候肌索,第一次點擊并不會執(zhí)行onClick()
方法蕉拢,而是執(zhí)行onFocusChange()
。第二次點擊的時候才會執(zhí)行onClick()
方法≡位唬看起來好像onFocusChange()
消耗了點擊事件午乓,實際上并不是的。
這個問題我們看一下源碼就清楚了:
onClick()
方法是在onTouchEvent的ACTION_UP里調(diào)用的届巩,看一下View的onTouchEvent方法:
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
......
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
......
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
可以看到硅瞧,只有當(dāng)focusTaken為false的時候才會執(zhí)行onClick,focusTaken的值默認(rèn)是false的恕汇,但是在isFocusable() && isFocusableInTouchMode() && !isFocused()
為true的時候,會去requestFocus
獲取焦點或辖,并將值賦給focusTaken瘾英。
關(guān)鍵在于isFocused()
,如果當(dāng)前Button沒有獲取焦點颂暇,isFocused()
返回false缺谴,!isFocused()
值為ture,Button就會去獲取焦點耳鸯,從而導(dǎo)致focusTaken
為true湿蛔,onClick
方法就不會執(zhí)行了,只有Button已經(jīng)獲取了焦點的時候才會執(zhí)行onClick方法县爬。