Compose 中的可见性跟踪

跟踪界面元素何时在屏幕上可见,对于各种应用场景都很有帮助,例如记录分析数据、管理界面状态,以及通过自动播放或暂停视频内容来优化资源。Compose 提供了多个修饰符来跟踪界面元素的可见性,例如:

  • onVisibilityChanged - 此修饰符会在可组合项的可见性发生变化时通知您。它非常适合在每次可组合项变为可见时触发操作或副作用。
  • onLayoutRectChanged - 此修饰符提供有关可组合项相对于根、窗口和屏幕的边界的信息。它提供低级别控制,是 onVisibilityChanged 的基础 API。该修饰符与 onGloballyPositioned 类似,但性能更出色,灵活性更高。

您可以将这些 API 与任何可组合项搭配使用,作为修饰符链的一部分。

使用 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 修饰符提供一个布尔值,用于反映可组合项的当前可见性状态。此外,它还提供 minFractionVisible 和 minDurationMs 等参数,让您能够更精细地控制何时需要触发可见性回调。

与所有其他修饰符一样,onVisibilityChanged 修饰符的顺序也很重要。上面的示例展示了一个可组合函数,该函数可呈现带有内边距的文本。为确保修饰符影响整个可组合项以及内边距,请在 padding 修饰符之前添加 onVisibilityChanged 修饰符。

在触发可见性回调之前,为可组合项设置时间限制

在某些情况下,您可能希望仅在某个内容对用户可见达到一定时间后才触发操作。例如,如果视频已向用户展示了一段时间,您可以自动播放该视频。

如需在某个项显示达到指定时长后触发操作,请使用 onVisibilityChanged 修饰符中的 minDurationMs 参数。此参数指定可组合项需要持续可见的最短时间,以便触发回调。如果可组合项在达到时长之前停止显示,计时器会重置。默认值为 0 毫秒。

以下代码段会在可组合项对用户可见 3 秒后将背景更改为紫色:

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. 可组合项在屏幕上连续显示 3 秒后,背景会从粉色变为梅红色。

设置最小可见比例

在处理可滚动内容(例如 LazyColumn)时,为可组合项的可见性回调设置最小可见比例非常有用,这有助于优化超出屏幕尺寸的项的数据提取。

在这种情况下,请使用 onVisibilityChanged 修饰符中的 minFractionVisible 参数来定义可组合项在屏幕上显示多少比例才会被标记为可见。 它支持 0.0f 到 1.0f 之间的浮点值,默认设置为 1.0f。1.0f 表示可组合项需要完全显示在屏幕上,或者如果可组合项大于视口,则需要填满整个视口。

当可见比例大于 minFractionVisible,或者可组合项完全可见或填满视口时,回调会收到 true。否则,它会收到 false。

LazyColumn(
    modifier = modifier.fillMaxSize()
) {
    item {
        Box(
            modifier = Modifier
                // ...
                // Here `visible` is `true` when more than 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 机器人。在图 2 中,第三个机器人未加载,因为可组合项未完全可见。在图 3 中,minFractionVisible 已设置,第三个机器人会在屏幕上完全可见之前加载。

隐藏可组合项并保留其空间

如需在不更改周围布局的情况下隐藏可组合项,请使用 visible 修饰符。当您传递 false 时,系统仍会测量可组合项,但不会放置或绘制它。与将 alpha 设置为 0f 不同,visible(false) 还会从无障碍功能树中移除元素并停用触摸互动,同时保留其布局空间。

以下示例展示了一个对勾图标,该图标在隐藏时仍会保留其空间,因此其旁边的文本不会移动:

Row(modifier, verticalAlignment = Alignment.CenterVertically) {
    Icon(
        painter = painterResource(R.drawable.check),
        contentDescription = "Saved",
        modifier = Modifier
            // The icon keeps its space while it's hidden, so the text doesn't move.
            .visible(isSaved)
    )
    Text("Draft", Modifier.padding(start = 8.dp))
}

当可组合项周围的布局在可组合项出现和消失时不得移动时,请使用 visible。如需移除可组合项及其空间,请勿调用它,或使用 AnimatedVisibility 为其添加淡入和淡出动画效果。