Compose笔记(八十三)--onVisibilityChanged

这一节主要了解一下Compose中onVisibilityChanged,它是用来监听组件可见状态变化,简单总结如下:

API onVisibilityChanged:拿到组件与视口的窗口坐标矩形,求矩形交集,计算重叠面积占组件自身总面积的比值

minDurationMs:可见状态持续防抖时间

minFractionVisible:最小可见面积占比阈值,默认 1.0

viewportBounds:自定义视口容器,可为 null。

callback:可见状态回调函数

场景:

1 列表曝光统计

2 组件自动播放控制

3 动画触发

栗子:

Kotlin 复制代码
mport android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onVisibilityChanged
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp


@Composable
fun VisiblitySample() {
    val list = (1..15).map { "Item $it" }
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        items(list) { itemText ->
            var logStr = "未曝光"
            Box(modifier = Modifier
                .fillMaxWidth()
                .height(120.dp)
                .padding(8.dp)
                .onVisibilityChanged(
                    minDurationMs = 0,
                    minFractionVisible = 0.5f 
                ) { isVisible ->
                    logStr = if (isVisible) "已曝光 $itemText" else "离开视口 $itemText"
                    println(logStr)
                }
            ) {
                Text(
                    text = "$itemText \n :50%可见触发",
                    modifier = Modifier.padding(12.dp),
                    textAlign = TextAlign.Center
                )
            }
        }
    }
}
Kotlin 复制代码
import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onVisibilityChanged
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp


data class Product(
    val id: String,
    val name: String,
    val price: Double
)


@Composable
fun FeedSample() {
    val products = remember {
        List(30) { Product(id = "SKU_$it", name = "高级商品 $it", price = 99.9 * it) }
    }
    val exposedMap = remember { mutableStateMapOf<String, Boolean>() }
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp)
    ) {
     
        items(
            items = products,
            key = { it.id }
        ) { product ->

            val isAlreadyExposed = exposedMap[product.id] == true

            ProductCard(
                product = product,
                isExposed = isAlreadyExposed,
                onExpose = {
                    exposedMap[product.id] = true
                    Log.d("EcommerceFeed", "[埋点上报] 商品有效曝光: ${product.name} (价格: ${product.price})")
                }
            )
        }
    }
}

@Composable
fun ProductCard(
    product: Product,
    isExposed: Boolean,
    onExpose: () -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .height(120.dp)
            .onVisibilityChanged(
                minDurationMs = 500,      
                minFractionVisible = 0.6f  
            ) { isVisible ->
                if (isVisible && !isExposed) {
                    onExpose()
                }
            }
    ) {
        Box(modifier = Modifier.fillMaxSize().padding(16.dp)) {
            Column(modifier = Modifier.align(Alignment.CenterStart)) {
                Text(text = product.name, fontSize = 18.sp)
                Text(text = "¥ ${product.price}", fontSize = 14.sp, color = Color.Red)
            }

            if (isExposed) {
                Text(
                    text = " 已曝光",
                    modifier = Modifier.align(Alignment.CenterEnd),
                    color = Color.Gray
                )
            }
        }
    }
}
相关推荐
Fa_Mian_Tuan4 小时前
图论基础|邻接矩阵超详细讲解(含无向/有向/带权图+完整可运行C语言代码)
c语言·数据结构·笔记·算法·图论
FakeOccupational6 小时前
【电路笔记 STM32】stm32f103 实现HAL_UART_Transmit_DMA + 普通模式/连续模式的 UART DMA 收发
笔记·stm32·嵌入式硬件
北京海得康7 小时前
DMD基因治疗deramiocel遭FDA质疑,Ultragenyx DTX401即将获批
笔记
zjnlswd7 小时前
C#学习笔记2 刘铁锰
笔记·学习
Mr_liu_6667 小时前
Claude非专业入门实战笔记(4):Claude运行方式简单解析——从RAG到代理循环
笔记·ai编程·claude
凯尔萨厮7 小时前
Git(学习笔记)
笔记·git·学习
蒸蒸yyyyzwd8 小时前
cpp选手备注秋招 MySQL学习笔记 day8
笔记·学习·求职招聘
AI直播技术杂谈8 小时前
本周技术笔记:直播推流的心跳检测与断线重连逻辑
笔记
九硕智慧建筑一体化厂家8 小时前
从照明节能到碳排可见:能碳平台助力机房迈向 “零碳” 未来
运维·笔记·智慧城市