lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

輸入事件

在 Android,有多種方法可以攔截使用者與應用程式互動的事件。 如果考慮的是使用者介面內的事件,方法就是從與使用者互動的特定檢視物件中擷取事件。 檢視類別提供執行此動作的方法。

在您用來撰寫版面配置的各種檢視類別中,您會發現多種公用回呼方法,對 UI 事件似乎相當實用。 當該物件發生個別動作時,Android 架構會呼叫這些方法。 例如,輕觸檢視 (例如按鈕) 時,會在該物件上呼叫 onTouchEvent() 方法。 不過,為了攔截這個事件,您必須延伸類別並覆寫方法。 然而,延伸每個檢視物件以便處理這類事件並不實際。 這就是檢視類別也包含巢狀介面與回呼的集合的原因,這樣您就能更輕鬆地定義。 這些介面稱為事件接聽器,就是用來擷取使用者與您 UI 互動的票券。

雖然您更常使用事件接聽器來接聽使用者互動,未來您可能會想要延伸檢視類別以建置自訂元件。 或許您想要延伸 Button 類別讓一些項目更為出色。 在這種情況下,您能夠使用類別事件處理常式來為您的類別定義預設事件行為。

事件接聽器

事件接聽器是 View 類別中的一個介面,該類別包含單一回呼方法。 當使用者與 UI 中的項目互動並觸發接聽器所註冊的檢視時,Android 架構就會呼叫這些方法。

事件接聽器介面包含下列回呼方法:

onClick()
View.OnClickListener。使用者輕觸項目 (處於輕觸模式時),或將焦點放在具有導覽鍵或軌跡球的項目上,然後按適當的 "enter" 鍵或按下軌跡球時,就會呼叫。
onLongClick()
View.OnLongClickListener。使用者輕觸並按住項目 (處於輕觸模式時),或將焦點放在具有導覽鍵或軌跡球的項目上,然後按住適當的 "enter" 鍵或按住軌跡球 (一秒) 時,就會呼叫。
onFocusChange()
View.OnFocusChangeListener。使用者使用導覽鍵或軌跡球導覽至項目或離開項目時,就會呼叫。
onKey()
View.OnKeyListener。使用者將焦點放在項目上,然後按下或放開裝置上的硬體鍵時,就會呼叫。
onTouch()
View.OnTouchListener。當使用者執行符合輕觸事件資格的動作時,包括按下、放開或在螢幕上的任何移動手勢 (在項目邊界內),就會呼叫。
onCreateContextMenu()
View.OnCreateContextMenuListener。建置操作選單時 (產生持續「長按」的效果),就會呼叫。 請參閱選單開發人員指南的操作選單相關討論。

這些方法是其個別介面的唯一要素。如要定義其中一種方法並處理您的事件,可在您的 Activity 中實作巢狀介面或將它定義為匿名類別。然後,將您的實作執行個體傳送至個別的 View.set...Listener() 方法。 (例如,呼叫 setOnClickListener(),將您的 OnClickListener 實作傳送給它。)

下列範例說明如何為某個按鈕註冊 on-click 接聽器。

// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(mCorkyListener);
    ...
}

您也會發現在 Activity 中實作 OnClickListener 會更為方便。這樣可避免額外的類別載入和物件配置。 例如:

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
    ...
}

請注意,上述範例的 onClick() 回呼不會傳回任何值,但某些其他事件接聽器方法必須傳回布林值。 這個原因取決於事件。 少數執行此事件的原因如下:

  • onLongClick() - 這會傳回一個布林值,指出您是否已使用此事件,未來不應該繼續執行。 亦即,傳回 true 指出您已處理事件,應該在這裡停止;如果您未處理事件和/或事件應該繼續在任何其他 on-click 接聽器上執行,則會傳回 false
  • onKey() - 這會傳回一個布林值,指出您是否已使用此事件,未來不應該繼續執行。 亦即,傳回 true 指出您已處理事件,應該在這裡停止;如果您未處理事件和/或事件應該繼續在任何其他 on-key 接聽器上執行,則會傳回 false
  • onTouch() - 這會傳回一個布林值,指出您的接聽器是否已使用此事件。 最重要的是,這個事件可以處理彼此接續的多個動作。 因此,收到向下動作事件時如果您傳回 false,就表示您尚未使用事件,而且對於這個事件的後續動作也不感興趣。 因此,您不需要在事件內執行任何其他動作,例如手指手勢或最終動作事件。

請記住,硬體按鍵事件一律會傳送至目前焦點中的檢視。它們會從檢視階層的最上層開始發送,然後往下直到到達適當的目的地為止。 如果焦點現在位於您的檢視 (或檢視的子項),則您可以透過 dispatchKeyEvent() 方法查看事件過程。 作為透過您的檢視擷取按鍵事件的替代方法,您也可以使用 onKeyDown()onKeyUp() 接收您 Activity 內的所有事件。

此外,當您思考應用程式的文字輸入時,請記住,許多裝置只有軟體輸入方法。 這類方法不需要以按鍵為基礎;有些可能會使用語音輸入、手寫等方式。即使輸入方法出現類似鍵盤的介面,也通常不會觸發事件的 onKeyDown() 系列。 您不應該建置需要按下特定按鍵才能控制的 UI,除非您想將應用程式限制為使用硬體鍵盤的裝置。 尤其是當使用者按 Return 鍵時,不要藉助這些方法來驗證輸入;改為使用像 IME_ACTION_DONE 的動作向輸入方法示意您應用程式預期的反應方式,讓它能夠以有意義的方式變更其 UI。 避免假設軟體輸入方法應該會如何運作,只要相信它能為您的應用程式提供既有的格式化文字。

注意:Android 會先呼叫事件處理常式,然後再從類別定義呼叫適當的預設處理常式。 因此,從這些事件接聽器傳回 true 將會停止將事件傳播到其他事件接聽器,也會封鎖對檢視中預設事件處理常式的回呼。 因此,要確定您傳回 true 時要終止事件。

事件處理常式

如果您正從檢視建置自訂元件,則您就能定義多種回呼方法做為預設事件處理常式。在自訂元件的相關文件中,您將瞭解事件處理常式的一些常見回呼,包括:

您還必須注意其他一些方法,這些方法不屬於檢視類別,但會直接影響您能夠處理事件的方式。 因此,在版面配置中管理更複雜的事件時,請考量下列其他方法:

輕觸模式

使用者以方向鍵或軌跡球瀏覽使用者介面時,必須對可動作的項目 (例如按鈕) 提供焦點,這樣使用者就能看到什麼項目將接受輸入。 不過,如果裝置具有輕觸功能,而且使用者透過輕觸方式開始與介面互動,就不需要再將項目反白顯示,或是對特定檢視提供焦點。 因此,這就是名稱為「輕觸模式」的互動模式。

如果是具備輕觸功能的裝置,使用者輕觸螢幕之後,裝置就會進入輕觸模式。 從這點以此類推,只有 isFocusableInTouchMode() 為 true 的檢視才可設定焦點,例如文字編輯小工具。 其他可輕觸的檢視,例如按鈕,在輕觸時不會成為焦點;按下時,只會觸發 on-click 接聽器。

使用者在任何時候點擊方向鍵或使用軌跡球捲動時,裝置會結束輕觸模式,然後找尋要成為焦點的檢視。 現在,使用者可繼續與使用者介面互動,而不必輕觸螢幕。

整個系統 (所有視窗和 Activity) 都會保留輕觸模式的狀態。如要查詢目前的狀態,您可以呼叫 isInTouchMode() 以查看裝置目前是否處於輕觸模式。

處理焦點

架構會處理慣例焦點移動以回應使用者輸入。 這包括在移除或隱藏檢視時變更焦點,或是新檢視可用時。 檢視可透過 isFocusable() 方法指出它們成為焦點的意願。 如要變更檢視是否可成為焦點,可呼叫 setFocusable()。 處於輕觸模式時,您可使用 isFocusableInTouchMode() 查詢檢視是否允許成為焦點。 您可以使用 setFocusableInTouchMode() 進行變更。

焦點移動是以演算法為依據,在指定的方向尋找最接近的項目。 在少數情況下,預設的演算法與開發人員預期的行為可能不符。 在這些情況下,您可以在版面配置檔案使用下列 XML 屬性進行明確的覆寫: nextFocusDownnextFocusLeftnextFocusRightnextFocusUp。在移出焦點的檢視中,新增下列其中一個屬性。 將屬性的值定義為應該成為焦點之檢視的 ID。 例如:

<LinearLayout
    android:orientation="vertical"
    ... >
  <Button android:id="@+id/top"
          android:nextFocusUp="@+id/bottom"
          ... />
  <Button android:id="@+id/bottom"
          android:nextFocusDown="@+id/top"
          ... />
</LinearLayout>

一般來說,在這個直式版面配置中,從第一個按鈕往上瀏覽或從第二個按鈕往下瀏覽都不會到任何地方。 現在,上方按鈕已將下方按鈕定義為 nextFocusUp (反之亦然),導覽焦點會從上到下以及從下到上循環。

如果您想在 UI 中將檢視宣告為可設定焦點 (傳統上不行),可在您的版面配置宣告中將 android:focusable XML 屬性新增至檢視。 將值設定為 true。您也可以使用 android:focusableInTouchMode 在輕觸模式中將檢視宣告為可設定焦點。

如要要求特定檢視成為焦點,可呼叫 requestFocus()

如要接聽焦點事件 (在檢視獲得或失去焦點時收到通知),可使用 onFocusChange() (如上述事件接聽器中所討論)。