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
                )
            }
        }
    }
}
相关推荐
一隅论数智5 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
深圳老胡6 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
Because_of_Her16 天前
并查集-听课笔记
笔记·算法·并查集
彧azz6 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
陈卫军老师6 天前
陈卫军:把口味写在一张纸上,店才稳得住
经验分享·笔记·流量运营
`流年づ6 天前
人工智能学习笔记 - 补充
人工智能·笔记·深度学习·学习
qeen876 天前
【Linux】操作系统之进程介绍(二)
linux·笔记·学习·进程
从零开始的嵌入式之旅6 天前
day47
arm开发·经验分享·笔记·嵌入式硬件
陈年老古董6 天前
MediaPipe 姿态检测与脸部关键点检测
笔记·python·opencv·学习·dlib
彧azz6 天前
操作系统时间管理与系统核心板块学习总结
c语言·笔记·学习·系统架构