輸入事件總覽

嘗試 Compose 方法
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中使用觸控和輸入功能。

在 Android 上,您可以透過幾種方式攔截使用者與應用程式互動的事件。當您考慮使用者介面中的事件時,方法是從與使用者互動的特定 View 物件擷取事件。View 類別提供執行這項作業的方法。

在您用來組合版面配置的各種 View 類別中,您可能會發現一些公開回呼方法適合用於 UI 事件。Android 架構會在該物件上發生相應動作時呼叫這些方法。舉例來說,使用者輕觸檢視畫面 (例如按鈕) 時,系統會在該物件上呼叫 onTouchEvent() 方法。不過,為了攔截這個情況,您必須擴充該類別並覆寫方法。但是,擴充每個 View 物件來處理這類事件並不實際。因此,View 類別也包含一組巢狀介面,以及您可以更輕鬆地定義的回呼。這些介面稱為事件監聽器,可讓您擷取使用者與 UI 的互動情形。

雖然您較常使用事件監聽器來監聽使用者互動,但有時您可能會想要擴充 View 類別,以便建構自訂元件。您可能會想擴充 Button 類別,讓更多功能更臻完善。在這種情況下,您可以使用類別事件處理常式,為類別定義預設事件行為。

事件監聽器

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

事件監聽器介麵包含下列回呼方法:

onClick()
來自 View.OnClickListener。使用者輕觸項目 (觸控模式時)、使用瀏覽鍵或軌跡球將焦點移至項目,然後按下合適的「Enter」鍵或按下軌跡球時,系統就會呼叫此方法。
onLongClick()
來自 View.OnLongClickListener。當使用者輕觸並按住項目 (觸控模式下) 時,或者將焦點移至具有瀏覽鍵或軌跡球的項目,然後按住適用的「Enter」鍵,或按住軌跡球 (一秒並按住) 時,系統就會呼叫此方法。
onFocusChange()
來自 View.OnFocusChangeListener。當使用者使用導覽鍵或軌跡球前往或離開項目時,系統就會呼叫此方法。
onKey()
來自 View.OnKeyListener。當使用者將焦點移至該項目,然後按下或放開裝置上的硬體金鑰時,系統就會呼叫此方法。
onTouch()
來自 View.OnTouchListener。當使用者執行符合觸控事件的動作時,系統就會呼叫此方法,這些動作包括按下、放開,或是螢幕上的任何動作手勢 (在項目邊界內)。
onCreateContextMenu()
來自 View.OnCreateContextMenuListener。在建立內容選單時 (持續「長按」作業的結果),系統就會呼叫此方法。請參閱「選單」開發人員指南中內容選單的相關討論。

這些方法是各自介面的唯一內外人。如要定義其中一種方法並處理事件,請在活動中實作巢狀介面,或將其定義為匿名類別。然後將實作的執行個體傳遞至各自的 View.set...Listener() 方法。(例如,呼叫 setOnClickListener() 並將 OnClickListener 的實作傳遞至此函式)。

以下範例說明如何註冊按鈕的點擊事件監聽器。

Kotlin

protected void onCreate(savedValues: Bundle) {
    ...
    val button: Button = findViewById(R.id.corky)
    // Register the onClick listener with the implementation above
    button.setOnClickListener { view ->
        // do something when the button is clicked
    }
    ...
}

Java

// Create an anonymous implementation of OnClickListener
private OnClickListener corkyListener = 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(corkyListener);
    ...
}

此外,將 OnClickListener 實作為 Activity 會更方便。這可避免載入多餘的類別和分配物件。例如:

Kotlin

class ExampleActivity : Activity(), OnClickListener {
  
    protected fun onCreate(savedValues: Bundle) {
        val button: Button = findViewById(R.id.corky)
        button.setOnClickListener(this)
    }

    // Implement the OnClickListener callback
    fun onClick(v: View) {
        // do something when the button is clicked
    }
}

Java

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 表示已經處理該事件,應該就此停止;傳回 false 表示尚未處理該事件,以及/或者該事件應繼續前往任何其他點擊事件監聽器。
  • onKey() - 這會傳回一個布林值,指出您是否已取用該事件,且不應繼續保留。 也就是說,傳回 true 表示您已處理該事件,應該就此停止;傳回 false 表示尚未處理該事件,及/或事件應繼續前往任何其他按鍵事件監聽器。
  • onTouch() - 這會傳回布林值,表示事件監聽器是否取用這個事件。重要的是,這個事件可能有多個後續動作。因此,在收到向下動作事件時傳回 false,就表示尚未取用該事件,也對這個事件的後續動作不感興趣。因此,系統不會針對事件中的任何其他動作 (例如手指手勢或最終的向上操作事件) 呼叫您。

請注意,系統一律會將硬體按鍵事件傳送至目前焦點所在的檢視畫面。系統會從檢視區塊階層頂端開始傳送,再向下分派,直到達到適當的目的地為止。如果您的檢視畫面 (或檢視畫面的子項) 目前有焦點,您可以透過 dispatchKeyEvent() 方法查看事件移動。除了透過 View 擷取重要事件之外,您也可以用 onKeyDown()onKeyUp() 接收 Activity 中的所有事件。

此外,在考慮為應用程式輸入文字時,請記得許多裝置只有軟體輸入法。這類方法不必以金鑰為基礎;有些可能會使用語音輸入、手寫等。即使輸入法呈現類似鍵盤的介面,通常也「不會」觸發 onKeyDown() 事件系列。除非您想將應用程式限制為具有硬體鍵盤的裝置,否則請勿建構需要按下特定按鍵進行控制的 UI。請特別注意,當使用者按下傳回金鑰時,請勿仰賴這些方法驗證輸入內容;請改用 IME_ACTION_DONE 等動作告知輸入方法,指出應用程式預期回應的方式,因此可能會以有意義的方式變更 UI。請避免假設軟體輸入法的運作方式,只要信任它能為應用程式提供已格式化的文字即可。

注意:Android 會先呼叫事件處理常式,再從類別定義呼叫適當的預設處理常式。因此,從這些事件監聽器回傳 true 會停止將事件傳播至其他事件監聽器,也會封鎖 View 中預設事件處理常式的回呼。因此,在傳回 true 時,請務必確認您希望終止事件。

事件處理常式

如果您是透過 View 建構自訂元件,就可以定義多個回呼方法,做為預設事件處理常式。在自訂檢視區塊元件的文件中,您可以瞭解一些常見的回呼用於事件處理,包括:

還有一些其他方法您應該瞭解,雖然這些方法並不屬於 View 類別,但會直接影響處理事件的方式。因此,在版面配置中管理更複雜的事件時,請考慮以下其他方法:

觸控模式

使用者透過方向鍵或軌跡球瀏覽使用者介面時,請務必將焦點放在可操作的項目 (例如按鈕),以便使用者看到可接受輸入的內容。不過,如果裝置具備觸控功能,且使用者開始藉由輕觸介面與介面互動,就沒有必要醒目顯示項目,或聚焦於特定 View。因此,有一種互動模式稱為「觸控模式」。

如果是觸控式裝置,只要使用者輕觸螢幕,裝置就會進入觸控模式。從現在起,只有 isFocusableInTouchMode() 為「是」的檢視畫面會成為焦點,例如文字編輯小工具。其他可輕觸的檢視畫面 (例如按鈕) 不會在輕觸時聚焦;這些檢視畫面只會在按下時觸發點擊事件監聽器。

每當使用者按一下方向鍵,或使用軌跡球捲動時,裝置就會結束觸控模式,並找到要聚焦的檢視畫面。現在,使用者不必觸碰螢幕,就能繼續與使用者介面互動。

觸控模式狀態會整個系統 (所有視窗和活動) 保持不變。如要查詢目前的狀態,您可以呼叫 isInTouchMode() 來瞭解裝置目前是否處於觸控模式。

處理焦點

架構會處理例行焦點移動,以回應使用者輸入內容。包括在檢視畫面移除或隱藏,或有新的檢視畫面可用時變更焦點。檢視畫面表示他們願意透過 isFocusable() 方法聚焦。如要變更檢視畫面是否可以聚焦,請呼叫 setFocusable()。使用觸控模式時,您可以查詢檢視畫面是否允許使用 isFocusableInTouchMode() 聚焦。如要變更這項設定,請使用 setFocusableInTouchMode()

在搭載 Android 9 (API 級別 28) 以上版本的裝置中,活動不會指派初始焦點。相對的,您必須視需要明確要求初始焦點。

焦點動作是以演算法尋找特定方向中最接近的位置。在極少數情況下,預設演算法可能會與開發人員的預期行為不相符。在這些情況下,您可以在版面配置檔案中使用下列 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 中將 View 宣告為可聚焦 (傳統上來說並非可聚焦),請在版面配置宣告中,將 android:focusable XML 屬性新增至檢視畫面。設定 true 值。您也可以在觸控模式下,使用 android:focusableInTouchMode 將檢視畫面宣告為可聚焦。

如要要求特定檢視畫面接受焦點,請呼叫 requestFocus()

如要監聽焦點事件 (在檢視畫面收到或失去焦點時收到通知),請使用 onFocusChange(),詳情請參閱「事件監聽器」一節。