將焦點目標分組

您可以使用 focusGroup 修飾符,將多個焦點目標分組。分組功能可讓您管理焦點階層、隔離邏輯 UI 區域 (例如工具列、對話方塊動作或資訊卡清單),以及在焦點進入或離開區域時進行攔截。

焦點團體概念:進入、退出及預設遍歷

焦點群組會在子項焦點目標周圍建立連貫的瀏覽邊界。如要瞭解焦點如何跨越這個界線移動,需要掌握兩個重要概念:

  • 進入:當焦點從焦點群組外的任何元素,轉移至群組內的元素時,就會觸發這個事件。
  • 離開:當焦點離開群組的最後一個內部元素,並轉換為外部焦點目標時,就會發生這個事件。
這張圖表顯示焦點團體邊界之間的進入和結束轉場效果。
圖 1. 焦點團體,包含進入和離開事件。

預設焦點遍歷行為

根據預設,當焦點群組從外部接收焦點時:

  1. 進入群組:Compose 會自動選取內部子項焦點目標。如果是單一維度 (Tab) 導覽,系統會依視覺外觀順序選取第一個子項。如果是二維 (箭頭鍵或 D-Pad) 導覽,系統會選取幾何上最接近輸入方向的子項。
  2. 在群組內導覽:重複按下導覽鍵,即可在群組封閉的同層級焦點目標之間移動焦點。
  3. 離開群組:使用者瀏覽過群組內最後一個焦點目標後,下次按下按鍵時就會離開群組,並將焦點移至群組外相鄰的焦點目標。

自訂焦點項目重新導向

在許多 UI 設計中,預設的進入目標 (例如外觀順序中的第一個子項) 並非最符合邏輯或最方便使用者的選擇。

意圖和用途

請考慮使用確認對話方塊,左側為「取消」按鈕,右側為主要「確認」按鈕。使用者從表單欄位向下瀏覽至按鈕列時:

  • 預設行為:焦點會落在「取消」上,因為這是視覺外觀順序中的第一個按鈕。
  • 預期行為:「確認」是主要建議動作,因此當您從焦點順序較早的位置進入按鈕群組時,焦點可能會直接落在「確認」上,但使用者仍可視需要按下「向左」選取「取消」。
按鈕群組的預設焦點項目。
圖 2. 預設焦點項目目標的「取消」和「確認」按鈕。

其他常見用途包括:

  • 在輸入 TabRow 時,直接將焦點移至目前所選分頁。
  • 進入媒體播放列時,直接將焦點移至「播放 / 暫停」控制項。

使用 onEnter 和 FocusRequester 實作

如要在進入焦點團體時重新導向焦點,請按照下列步驟操作:

  1. 將 focusGroup 修飾符套用至封閉相關焦點目標的上層容器。
  2. 將 focusProperties 修飾符套用至容器,並設定 onEnter 回呼。
  3. 在 onEnter 回呼 (範圍為 FocusEnterExitScope) 中,使用 focusRequester,在與偏好的預設子項相關聯的 FocusRequester 上呼叫 requestFocus()。

val defaultChildRequester = remember { FocusRequester() }

Row(
    modifier = Modifier
        .focusGroup()
        .focusProperties {
            // Intercept entry into this group and redirect focus to the primary action
            onEnter = {
                defaultChildRequester.requestFocus()
            }
        }
) {
    Button(onClick = { /* Cancel action */ }) {
        Text("Cancel")
    }
    Button(
        onClick = { /* Confirm action */ },
        modifier = Modifier.focusRequester(defaultChildRequester)
    ) {
        Text("Confirm (Default)")
    }
}

在 onEnter 和 onExit 內,您也可以呼叫 cancelFocusChange(),完全封鎖邊界間的焦點轉移,或檢查 requestedFocusDirection,根據使用者是否使用 Tab、Down 或 Left 鍵導覽,自訂路徑。

可捲動容器預設為焦點群組

在 Jetpack Compose 中,LazyRow、LazyColumn 和 LazyVerticalGrid 等可捲動的容器會自動做為焦點群組。您不需要明確將 focusGroup 修飾符套用至這些項目,即可設定 onEnter 或 onExit 回呼。