Кнопки с иконками

Кнопки-значки отображают действия, которые могут выполнять пользователи. Кнопки-значки должны использовать значок с понятным значением и, как правило, представлять общие или часто используемые действия.

Существует два типа кнопок-значков:

  • По умолчанию : эти кнопки могут открывать другие элементы, такие как меню или поиск.
  • Переключение : эти кнопки могут представлять двоичные действия, которые можно включать и выключать, например, «избранное» или «закладка».
5 кнопок-значков с различными значками (настройки, еще и т. д.). Некоторые из них заполнены, что указывает на выбор, а некоторые обведены.
Рисунок 1. Кнопки-иконки, некоторые из которых закрашены (что указывает на выбор) и обведены.

API поверхность

Используйте IconButton composable для реализации стандартных кнопок со значками. Для создания различных визуальных стилей, таких как заполненные, заполненные тонально или обведенные, используйте FilledIconButton , FilledTonalIconButton и OutlinedIconButton соответственно.

Ключевые параметры IconButton включают в себя:

  • onClick : лямбда-функция, которая выполняется, когда пользователь нажимает кнопку со значком.
  • 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 перестраивает пользовательский интерфейс всякий раз, когда его значение изменяется.
    • rememberSaveable обеспечивает сохранение состояния isToggled при изменении конфигурации, например при повороте экрана.
  • Лямбда-функция onClick элемента IconButton определяет поведение кнопки при нажатии, переключая состояние между true и false .
  • Параметр painter компонуемого Icon условно загружает другой painterResource на основе состояния isToggled . Это изменяет внешний вид значка.
    • Если isToggled имеет true , загружается закрашенное сердце.
    • Если isToggled имеет значение false , загружается выделенное сердце.
  • contentDescription Icon также обновляется в зависимости от состояния 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 , идентификатор отрисовываемого ресурса для значка, когда кнопка не нажата, и selectedImage: Int , идентификатор отрисовываемого ресурса для значка, когда кнопка нажата.
  • Он использует interactionSource для отслеживания взаимодействий пользователя с помощью «нажатий».
  • isPressed имеет значение true, когда кнопка активно нажимается, и false в противном случае. Когда isPressed имеет значение true , LaunchedEffect входит в цикл.
    • Внутри этого цикла используется delay ( stepDelay ) для создания пауз между запускаемыми действиями. coerceIn гарантирует, что задержка составит не менее 1 мс, чтобы предотвратить бесконечные циклы.
    • pressedListener вызывается после каждой задержки в цикле. Это заставляет действие повторяться.
  • pressedListener использует rememberUpdatedState , чтобы гарантировать, что лямбда-функция onClick (действие, которое нужно выполнить) всегда является самой актуальной из последней композиции.
  • 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 отображает Row , содержащую два экземпляра MomentaryIconButton , и компонуемый Text для создания пользовательского интерфейса для увеличения и уменьшения счетчика.
  • Он поддерживает переменную изменяемого состояния pressedCount с помощью remember и mutableIntStateOf , инициализированную значением 0. Когда pressedCount изменяется, любые компонуемые объекты, наблюдающие за ним (например, компонуемый Text ), перестраиваются, чтобы отразить новое значение.
  • Первая MomentaryIconButton уменьшает pressedCount при нажатии или удержании.
  • Вторая MomentaryIconButton увеличивает pressedCount при нажатии или удержании.
  • Обе кнопки используют stepDelay в 100 миллисекунд, что означает, что действие onClick повторяется каждые 100 мс, пока удерживается кнопка.

Результат

В следующем видео показан пользовательский интерфейс с иконками кнопок и счетчиком:

Рисунок 3. Пользовательский интерфейс счетчика с двумя кнопками-значками (плюс и минус), которые увеличивают и уменьшают счетчик.

Дополнительные ресурсы