圖示按鈕

圖示按鈕會顯示使用者可執行的動作。圖示按鈕必須使用含義明確的圖示,通常代表常見或常用的動作。

圖示按鈕分為兩種類型:

  • 預設:這些按鈕可開啟其他元素,例如選單或搜尋。
  • 切換鈕:這些按鈕可代表能切換開啟或關閉的二進位動作,例如「收藏」或「書籤」。
5 個圖示按鈕,分別顯示不同圖示 (設定、更多等)。部分圖示為實心,表示已選取,部分圖示則為空心。
圖 1. 圖示按鈕,部分為實心 (表示已選取) 和空心。

API 介面

使用 IconButton 可組合項實作標準圖示按鈕。如要建立不同的視覺樣式 (例如填滿、填滿色調或外框),請分別使用 FilledIconButton、FilledTonalIconButton 和 OutlinedIconButton。

IconButton 的重要參數包括:

  • onClick:使用者輕觸圖示按鈕時執行的 lambda 函式。
  • enabled:控制按鈕啟用狀態的布林值。當 false 時,按鈕不會回應使用者輸入內容。
  • content:按鈕內的可組合內容,通常是 Icon。

基本範例:切換圖示按鈕

這個範例說明如何實作切換圖示按鈕。切換圖示按鈕的外觀會根據是否選取而改變。

@Preview
@Composable
fun ToggleIconButtonExample() {
    // isToggled initial value should be read from a view model or persistent storage.
    var isToggled by rememberSaveable { mutableStateOf(false) }

    IconButton(
        onClick = { isToggled = !isToggled }
    ) {
        Icon(
            painter = if (isToggled) painterResource(R.drawable.favorite_filled) else painterResource(R.drawable.favorite),
            contentDescription = if (isToggled) "Selected icon button" else "Unselected icon button."
        )
    }
}

程式碼重點

  • ToggleIconButtonExample 可組合項會定義可切換的 IconButton。
    • mutableStateOf(false) 會建立一個 MutableState 物件,其中包含布林值,初始值為 false。這會使 isToggled 成為狀態容器,也就是說,每當值變更時,Compose 都會重組 UI。
    • rememberSaveable 可確保 isToggled 狀態在設定變更 (例如螢幕旋轉) 時仍能保留。
  • IconButton 的 onClick lambda 會定義按鈕點擊時的行為,在 true 和 false 之間切換狀態。
  • Icon 可組合項的 painter 參數會根據 isToggled 狀態,有條件地載入不同的 painterResource。這會變更圖示的外觀。
    • 如果 isToggled 為 true,則會載入填滿的愛心可繪項目。
    • 如果 isToggled 為 false,則會載入愛心外框可繪項目。
  • Icon 的 contentDescription 也會根據 isToggled 狀態更新,提供適當的無障礙資訊。

結果

下圖顯示上述程式碼片段中,切換圖示按鈕未選取的狀態:

未選取 (未填滿) 狀態下的「收藏」切換圖示按鈕 (心形)。
圖 2. 未選取狀態的「收藏」切換圖示按鈕。

進階範例:按下時重複執行動作

本節說明如何建立圖示按鈕,讓使用者按住按鈕時持續觸發動作,而非每次點擊只觸發一次。

@Composable
fun MomentaryIconButton(
    unselectedImage: Int,
    selectedImage: Int,
    contentDescription: String,
    modifier: Modifier = Modifier,
    stepDelay: Long = 100L, // Minimum value is 1L milliseconds.
    onClick: () -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    val isPressed by interactionSource.collectIsPressedAsState()
    val pressedListener by rememberUpdatedState(onClick)

    LaunchedEffect(isPressed) {
        while (isPressed) {
            delay(stepDelay.coerceIn(1L, Long.MAX_VALUE))
            pressedListener()
        }
    }

    IconButton(
        modifier = modifier,
        onClick = onClick,
        interactionSource = interactionSource
    ) {
        Icon(
            painter = if (isPressed) painterResource(id = selectedImage) else painterResource(id = unselectedImage),
            contentDescription = contentDescription,
        )
    }
}

程式碼重點

  • MomentaryIconButton 採用 unselectedImage: Int (未按下按鈕時圖示的可繪製資源 ID) 和 selectedImage: Int (按下按鈕時圖示的可繪製資源 ID)。
  • 它會使用 interactionSource,專門追蹤使用者的「按下」互動。
  • 當按鈕處於按下狀態時,isPressed 為 true,否則為 false。當 isPressed 為 true 時,LaunchedEffect 會進入迴圈。
    • 在這個迴圈中,系統會使用 delay (搭配 stepDelay) 在觸發動作之間建立暫停。coerceIn 可確保延遲時間至少為 1 毫秒,防止無限迴圈。
    • 每次迴圈延遲後,系統都會叫用 pressedListener。這會讓動作重複。
  • pressedListener 會使用 rememberUpdatedState,確保 onClick lambda (要執行的動作) 一律是最新組合中的最新版本。
  • Icon 會根據按鈕目前是否按下,變更顯示的圖片。
    • 如果 isPressed 為 true,則會顯示 selectedImage。
    • 否則會顯示 unselectedImage。

接下來,請在範例中使用這個 MomentaryIconButton。下列程式碼片段示範兩個控制計數器的圖示按鈕:

@Preview()
@Composable
fun MomentaryIconButtonExample() {
    var pressedCount by remember { mutableIntStateOf(0) }

    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_rewind,
            selectedImage = R.drawable.fast_rewind_filled,
            stepDelay = 100L,
            onClick = { pressedCount -= 1 },
            contentDescription = "Decrease count button"
        )
        Spacer(modifier = Modifier)
        Text("advanced by $pressedCount frames")
        Spacer(modifier = Modifier)
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_forward,
            selectedImage = R.drawable.fast_forward_filled,
            contentDescription = "Increase count button",
            stepDelay = 100L,
            onClick = { pressedCount += 1 }
        )
    }
}

程式碼重點

  • MomentaryIconButtonExample 可組合函式會顯示包含兩個 MomentaryIconButton 執行個體的 Row,以及 Text 可組合函式,用於建構 UI 來增加及減少計數器。
  • 它會使用 remember 和 mutableIntStateOf 維護 pressedCount 可變動狀態變數,並初始化為 0。當 pressedCount 變更時,任何觀察該值的可組合函式 (例如 Text 可組合函式) 都會重組,以反映新值。
  • 點選或按住第一個 MomentaryIconButton,可減少 pressedCount。
  • 第二個 MomentaryIconButton 則會在點選或按住時增加 pressedCount。
  • 兩個按鈕都使用 100 毫秒的 stepDelay,這表示按住按鈕時,onClick 動作每 100 毫秒重複一次。

結果

以下影片顯示含有圖示按鈕和計數器的 UI:

圖 3. 計數器 UI,包含兩個圖示按鈕 (加號和減號),可增加及減少計數器。

其他資源