Отслеживание видимости в Compose

Отслеживание видимости элемента интерфейса на экране полезно в различных ситуациях, например при регистрации аналитических данных, управлении состоянием интерфейса и оптимизации ресурсов путем автоматического воспроизведения или приостановки видеоконтента. В Compose есть несколько модификаторов для отслеживания видимости элементов интерфейса, например:

  • onVisibilityChanged – этот модификатор уведомляет вас, когда меняется видимость элемента, созданного с помощью функции composable. Он идеально подходит для запуска действия или побочного эффекта каждый раз, когда становится видимым компонуемый элемент.
  • onLayoutRectChanged – этот модификатор предоставляет информацию о границах композиции относительно корневого элемента, окна и экрана. Он обеспечивает низкоуровневое управление и является базовым API для onVisibilityChanged. Модификатор похож на onGloballyPositioned, но обеспечивает более высокую эффективность и гибкость.

Эти API можно использовать с любой composable-функцией, входящей в цепочку модификаторов.

Отслеживание изменений видимости с помощью onVisibilityChanged

Понимание того, когда элемент виден пользователю полностью или частично, может помочь вам отслеживать аналитику (например, количество просмотров), оптимизировать производительность (извлекать или предварительно извлекать данные из сети только тогда, когда элемент виден) или даже запускать события (воспроизводить или приостанавливать видео).

Чтобы получать уведомления об изменении видимости элемента, используйте модификатор onVisibilityChanged, как показано в следующем примере:

Text(
    text = "Some text",
    modifier = Modifier
        .onVisibilityChanged { visible ->
            if (visible) {
                // Do something if visible
            } else {
                // Do something if not visible
            }
        }
        .padding(vertical = 8.dp)
)

Модификатор onVisibilityChanged предоставляет логическое значение, отражающее текущее состояние видимости композиции. Кроме того, в нем есть параметры, например minFraction и minDurationMs, которые позволяют более точно настроить момент срабатывания обратного вызова видимости.

Как и в случае с другими модификаторами, при использовании модификатора onVisibilityChanged важна последовательность. В примере выше показана composable-функция, которая отрисовывает текст с отступами. Чтобы модификатор влиял на весь компонент вместе с отступами, добавьте модификатор onVisibilityChanged перед модификатором padding.

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

В некоторых случаях вам может понадобиться запустить действие только после того, как пользователь увидит определенный элемент в течение заданного времени. Например, вы можете настроить автозапуск видео, если оно показывается пользователю в течение определенного времени.

Чтобы действие запускалось после того, как объект будет виден в течение определенного времени, используйте параметр minDurationMs в модификаторе onVisibilityChanged. Этот параметр задает минимальное время, в течение которого компонент должен быть непрерывно виден, чтобы был вызван обратный вызов. Если компонуемый элемент перестанет быть видимым до истечения заданного времени, таймер будет сброшен. Значение по умолчанию – 0 миллисекунд.

В следующем фрагменте кода фон становится фиолетовым после того, как composable-функция будет видна пользователю в течение трех секунд:

var background by remember { mutableStateOf(PalePink) }
Card(
    modifier = modifier
        // ...
        .onVisibilityChanged(minDurationMs = 3000) {
            if (it) {
                background = MutedPlum
            }
        }
) {

    Box(
        modifier = Modifier
            // ...
            .background(background),
        contentAlignment = Alignment.Center,
    ) {
        // ...
    }
}

Рисунок 1. Фон меняется с розового на сливовый, когда компонент находится на экране в течение трех секунд.

Как задать минимальную видимую долю

Установка минимальной видимой доли для обратного вызова видимости композиции полезна при работе с контентом с возможностью прокрутки (например, LazyColumn), чтобы оптимизировать получение данных для элементов, которые превышают размер экрана.

В таких случаях используйте параметр minFractionVisible в модификаторе onVisibilityChanged, чтобы определить долю, которая должна быть на экране, чтобы компонуемый элемент был отмечен как видимый. Поддерживаются значения с плавающей запятой в диапазоне от 0.0f до 1.0f. По умолчанию установлено значение 1.0f. 1.0f означает, что компонент должен быть полностью виден на экране, чтобы сработал обратный вызов.

LazyColumn(
    modifier = modifier.fillMaxSize()
) {
    item {
        Box(
            modifier = Modifier
                // ...
                // Here the visible callback gets triggered when 20% of the composable is visible
                .onVisibilityChanged(
                    minFractionVisible = 0.2f,
                ) { visible ->
                    if (visible) {
                        // Call specific logic here
                        // viewModel.fetchDataFromNetwork()
                    }
                }
                .padding(vertical = 16.dp)
        ) {
            Text(
                text = "Sample Text",
                modifier = Modifier.padding(horizontal = 16.dp)
            )
        }
    }
}

Рисунок 2. Без указания minFractionVisible. Рисунок 3. Значение minFractionVisible – 0,2f.

В примере, который мы использовали ранее, боты Androidify выполняют предзагрузку из сети до того, как composable-функция станет полностью видимой. На рисунке 2 третий бот не загружается, так как компонуемый элемент виден не полностью. На рисунке 3 задано значение minFractionVisible, и третий бот загружается до того, как он полностью появится на экране.