Nút biểu tượng

Nút biểu tượng hiển thị các hành động mà người dùng có thể thực hiện. Nút biểu tượng phải sử dụng biểu tượng có ý nghĩa rõ ràng và thường biểu thị các thao tác phổ biến hoặc thường dùng.

Có hai loại nút biểu tượng:

  • Mặc định: Các nút này có thể mở các thành phần khác, chẳng hạn như trình đơn hoặc tìm kiếm.
  • Bật/tắt: Các nút này có thể đại diện cho các thao tác nhị phân có thể bật hoặc tắt, chẳng hạn như "yêu thích" hoặc "dấu trang".
5 nút biểu tượng có các biểu tượng khác nhau (cài đặt, khác, v.v.). Một số được tô màu, cho biết lựa chọn và một số được viền.
Hình 1. Các nút biểu tượng, một số nút được tô màu (cho biết lựa chọn) và được viền.

Nền tảng API

Sử dụng thành phần kết hợp IconButton để triển khai các nút biểu tượng tiêu chuẩn. Để tạo các kiểu hình ảnh khác nhau như tô màu, tô màu theo tông màu hoặc viền, hãy sử dụng FilledIconButton, FilledTonalIconButtonOutlinedIconButton tương ứng.

Các tham số chính của IconButton bao gồm:

  • onClick: Hàm lambda thực thi khi người dùng nhấn vào nút biểu tượng.
  • enabled: Một boolean kiểm soát trạng thái bật của nút. Khi false, nút này không phản hồi hoạt động đầu vào của người dùng.
  • content: Nội dung có thể kết hợp bên trong nút, thường là Icon.

Ví dụ cơ bản: Nút biểu tượng bật/tắt

Ví dụ này cho bạn biết cách triển khai nút biểu tượng bật/tắt. Nút biểu tượng bật/tắt sẽ thay đổi giao diện dựa trên trạng thái đã chọn hoặc chưa chọn.

@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."
        )
    }
}

Các điểm chính về mã

  • Thành phần kết hợp ToggleIconButtonExample xác định một IconButton có thể bật/tắt.
    • mutableStateOf(false) tạo một đối tượng MutableState chứa giá trị boolean, ban đầu là false. Điều này khiến isToggled trở thành trình giữ trạng thái, nghĩa là Compose sẽ kết hợp lại giao diện người dùng bất cứ khi nào giá trị của trình giữ trạng thái thay đổi.
    • rememberSaveable đảm bảo trạng thái isToggled vẫn tồn tại trên các thay đổi về cấu hình, chẳng hạn như xoay màn hình.
  • Lambda onClick của IconButton xác định hành vi của nút khi được nhấp, chuyển đổi trạng thái giữa truefalse.
  • Tham số painter của thành phần kết hợp Icon sẽ tải một painterResource khác theo điều kiện dựa trên trạng thái isToggled. Thao tác này sẽ thay đổi giao diện của biểu tượng.
    • Nếu isToggledtrue, thì hàm này sẽ tải hình trái tim có thể vẽ được.
    • Nếu isToggledfalse, thì lớp này sẽ tải hình trái tim có đường viền có thể vẽ.
  • contentDescription của Icon cũng cập nhật dựa trên trạng thái isToggled để cung cấp thông tin hỗ trợ tiếp cận phù hợp.

Kết quả

Hình ảnh sau đây cho thấy nút biểu tượng bật/tắt trong đoạn mã trước đó ở trạng thái chưa chọn:

Nút biểu tượng bật/tắt mục yêu thích (trái tim) ở trạng thái chưa chọn (chưa tô màu).
Hình 2. Nút biểu tượng bật/tắt "yêu thích" ở trạng thái chưa chọn.

Ví dụ nâng cao: Hành động lặp lại khi nhấn

Phần này minh hoạ cách tạo các nút biểu tượng liên tục kích hoạt một thao tác trong khi người dùng nhấn và giữ các nút đó, thay vì chỉ kích hoạt một lần cho mỗi lượt nhấp.

@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,
        )
    }
}

Các điểm chính về mã

  • MomentaryIconButton lấy unselectedImage: Int, mã nhận dạng tài nguyên có thể vẽ cho biểu tượng khi không nhấn nút và selectedImage: Int, mã nhận dạng tài nguyên có thể vẽ cho biểu tượng khi nhấn nút.
  • Phương thức này sử dụng interactionSource để theo dõi cụ thể các lượt tương tác "nhấn" của người dùng.
  • isPressed là true khi nút đang được nhấn và là false nếu không. Khi isPressedtrue, LaunchedEffect sẽ chuyển vào một vòng lặp.
    • Bên trong vòng lặp này, nó sử dụng delay (với stepDelay) để tạo khoảng tạm dừng giữa các hành động kích hoạt. coerceIn đảm bảo độ trễ tối thiểu là 1 mili giây để ngăn vòng lặp vô hạn.
    • pressedListener được gọi sau mỗi độ trễ trong vòng lặp. Thao tác này sẽ lặp lại.
  • pressedListener sử dụng rememberUpdatedState để đảm bảo rằng lambda onClick (thao tác cần thực hiện) luôn là thông tin mới nhất từ thành phần mới nhất.
  • Icon thay đổi hình ảnh hiển thị dựa trên việc nút hiện đang được nhấn hay không.
    • Nếu isPressed là true, selectedImage sẽ xuất hiện.
    • Nếu không, unselectedImage sẽ xuất hiện.

Tiếp theo, hãy sử dụng MomentaryIconButton này trong một ví dụ. Đoạn mã sau đây minh hoạ hai nút biểu tượng kiểm soát bộ đếm:

@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 }
        )
    }
}

Các điểm chính về mã

  • Thành phần kết hợp MomentaryIconButtonExample hiển thị một Row chứa hai thực thể MomentaryIconButton và một thành phần kết hợp Text để tạo giao diện người dùng cho việc tăng và giảm bộ đếm.
  • Phương thức này duy trì một biến trạng thái có thể thay đổi pressedCount bằng cách sử dụng remembermutableIntStateOf, được khởi tạo thành 0. Khi pressedCount thay đổi, mọi thành phần kết hợp quan sát thấy điều này (chẳng hạn như thành phần kết hợp Text) sẽ kết hợp lại để phản ánh giá trị mới.
  • MomentaryIconButton đầu tiên giảm pressedCount khi được nhấp hoặc giữ.
  • MomentaryIconButton thứ hai tăng pressedCount khi được nhấp hoặc giữ.
  • Cả hai nút đều sử dụng stepDelay là 100 mili giây, nghĩa là thao tác onClick sẽ lặp lại sau mỗi 100 mili giây khi một nút được giữ.

Kết quả

Video sau đây cho thấy giao diện người dùng với các nút biểu tượng và bộ đếm:

Hình 3. Giao diện người dùng của bộ đếm có hai nút biểu tượng (dấu cộng và dấu trừ) để tăng và giảm bộ đếm.

Tài nguyên khác