問題描述
我有一個包含兩個 EditText
的活動.我在第二個 EditText
字段上調(diào)用 ??requestFocus
因為默認(rèn)情況下焦點(diǎn)轉(zhuǎn)到第一個.焦點(diǎn)似乎在第二個字段中(第二個獲得突出顯示的邊框),但是如果我們嘗試使用硬件鍵盤輸入任何字符,文本會出現(xiàn)在第一個 EditText
控件中.任何想法為什么會發(fā)生?
I have an activity with two EditText
s. I am calling the requestFocus
on the second EditText
field since by default the focus goes to the first one. The focus appears to be in the second field (the second one gets the highlighted border), but if we try to enter any characters using the hardware keyboard the text appears in the first EditText
control. Any ideas why it would be happening?
推薦答案
很難說這是否是你的問題,但也不是不可能.
It's hard to tell whether this was your problem, but it's not unlikely.
TL;DR:永遠(yuǎn)不要從 onFocusChanged()
調(diào)用中調(diào)用像 requestFocus()
這樣的焦點(diǎn)更改方法.
TL;DR: Never call focus-changing methods like requestFocus()
from inside a onFocusChanged()
call.
問題在于 ViewGroup.requestChildFocus()
,其中包含:
The issue lies in ViewGroup.requestChildFocus()
, which contains this:
// We had a previous notion of who had focus. Clear it.
if (mFocused != child) {
if (mFocused != null) {
mFocused.unFocus();
}
mFocused = child;
}
在私有字段 mFocused
中,ViewGroup 存儲當(dāng)前具有焦點(diǎn)的子視圖(如果有).
Inside the private field mFocused
a ViewGroup stores the child view that currently has focus, if any.
假設(shè)您有一個 ViewGroup VG
,其中包含三個可聚焦視圖(例如 EditTexts)A
、B
和 C代碼>.
Say you have a ViewGroup VG
that contains three focusable views (e.g. EditTexts) A
, B
, and C
.
您已向 A
添加了一個 OnFocusChangeListener
(可能不是直接的,而是嵌套在其中的某處)在 B.requestFocus()
時調(diào)用 B.requestFocus()
code>A失去焦點(diǎn).
You have added an OnFocusChangeListener
to A
that (maybe not directly, but somewhere nested inside) calls B.requestFocus()
when A
loses focus.
現(xiàn)在假設(shè)A
有焦點(diǎn),用戶點(diǎn)擊C
,導(dǎo)致A
丟失,C
獲得焦點(diǎn).因為 VG.mFocused
當(dāng)前是 A
,所以 VG.requestChildFocus(C, C)
的上面部分然后翻譯成這樣:
Now imagine that A
has focus, and the user taps on C
, causing A
to lose and C
to gain focus. Because VG.mFocused
is currently A
, the above part of VG.requestChildFocus(C, C)
then translates to this:
if (A != C) {
if (A != null) {
A.unFocus(); // <-- (1)
}
mFocused = C; // <-- (3)
}
A.unFocus()
在這里做了兩件重要的事情:
A.unFocus()
does two important things here:
它將
A
標(biāo)記為不再具有焦點(diǎn).
It marks
A
as not having focus anymore.
它會調(diào)用你的焦點(diǎn)變化監(jiān)聽器.
It calls your focus change listener.
在該偵聽器中,您現(xiàn)在調(diào)用 B.requestFocus()
.這會導(dǎo)致 B
被標(biāo)記為具有焦點(diǎn),然后調(diào)用 VG.requestChildFocus(B, B)
.因為我們?nèi)匀簧钊胛矣?(1)
標(biāo)記的調(diào)用,所以 mFocused
的值仍然是 A
,因此這個內(nèi)部調(diào)用如下所示:
In that listener, you now call B.requestFocus()
. This causes B
to be marked as having focus, and then calls VG.requestChildFocus(B, B)
. Because we're still deep inside the call I've marked with (1)
, the value of mFocused
is still A
, and thus this inner call looks like this:
if (A != B) {
if (A != null) {
A.unFocus();
}
mFocused = B; // <-- (2)
}
這一次,對 A.unFocus()
的調(diào)用沒有做任何事情,因為 A
已經(jīng)被標(biāo)記為未聚焦(否則我們將進(jìn)行無限遞歸這里).此外,沒有任何事情將 C
標(biāo)記為未聚焦,這是 實際上 現(xiàn)在具有焦點(diǎn)的視圖.
This time, the call to A.unFocus()
doesn't do anything, because A
is already marked as unfocused (otherwise we'd have an infinite recursion here). Also, nothing happens that marks C
as unfocused, which is the view that actually has focus right now.
現(xiàn)在是 (2)
,它將 mFocused
設(shè)置為 B
.經(jīng)過更多的工作,我們終于從 (1)
處的調(diào)用返回,因此在 (3)
處,現(xiàn)在設(shè)置了 mFocused
的值到 C
,覆蓋之前的更改.
Now comes (2)
, which sets mFocused
to B
. After some more stuff, we finally return from the call at (1)
, and thus at (3)
the value of mFocused
is now set to C
, overwriting the previous change.
所以現(xiàn)在我們最終進(jìn)入了一個不一致的狀態(tài).B
和 C
都認(rèn)為他們有焦點(diǎn),VG
認(rèn)為 C
是有焦點(diǎn)的孩子.
So now we end up with an incosistent state. B
and C
both think they have focus, VG
considers C
to be the focused child.
特別是,按鍵以 C
結(jié)束,并且用戶不可能將焦點(diǎn)切換回 B
,因為 >B
認(rèn)為它已經(jīng)有了焦點(diǎn),因此不對焦點(diǎn)請求做任何事情;最重要的是,它不調(diào)用VG.requestChildFocus
.
In particular, keypresses end up in C
, and it is impossible for the user to switch focus back to B
, because B
thinks it already has focus and thus doesn't do anything on focus requests; most importantly, it does not call VG.requestChildFocus
.
推論:您也不應(yīng)該在 OnFocusChanged
處理程序中依賴 hasFocus()
調(diào)用的結(jié)果,因為在該調(diào)用中焦點(diǎn)信息不一致.
Corollary: You also shouldn't rely on results from hasFocus()
calls while inside an OnFocusChanged
handler, because the focus information is inconsistent while inside that call.
這篇關(guān)于多個 EditTexts 的焦點(diǎn)問題的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!