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

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

  • onVisibilityChanged – этот модификатор уведомляет вас, когда меняется видимость composable-функции. Он идеально подходит для запуска действия или побочного эффекта каждый раз, когда composable-функция становится видимой.
  • onLayoutRectChanged – этот модификатор предоставляет информацию о границах composable-функции относительно корня, окна и экрана. Он обеспечивает низкоуровневый контроль и является базовым 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 предоставляет логическое значение, которое отражает текущее состояние видимости composable-функции. Кроме того, в нем есть параметры minFraction и minDurationMs, которые позволяют точнее контролировать, когда должен срабатывать обратный вызов видимости.

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

Как задать ограничение по времени для composable-функции перед запуском обратного вызова видимости

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

Чтобы запустить действие после того, как элемент будет виден в течение определенного периода, используйте параметр minDurationMs в модификаторе onVisibilityChanged. Этот параметр указывает минимальное время, в течение которого composable-функция должна быть непрерывно видна, чтобы сработал обратный вызов. Если composable-функция перестает быть видимой до истечения этого времени, таймер сбрасывается. Значение по умолчанию – 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. Фон меняется с розового на сливовый после того, как composable-функция непрерывно находится на экране в течение трех секунд.

Укажите минимальную видимую долю

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

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

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 третий робот не загружается, так как composable-функция видна не полностью. На рисунке 3 задано значение minFractionVisible, и третий робот загружается до того, как он полностью виден на экране.