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
                )
            }
        }
    }
}
相关推荐
成都蜀味缘餐饮技术培训学校2 小时前
油炸串串技术培训实战指南,核心食材选购与预处理标准
数据仓库·经验分享·笔记·课程设计·微信公众平台
摇滚侠2 小时前
《大模型应用开发实践:基于 Spring AI+DeepSeek 实现》第 11 章 大模型技术概览 阅读笔记 1
人工智能·笔记·spring
xxwl5853 小时前
区域赛算法模版第八章---贪心(Greedy)
c++·笔记·学习·算法
知产xiao_xin4 小时前
专利立法及修改
经验分享·笔记·知识产权
qq_284274054 小时前
S7-1200 PLC硬件与启保停实训:CPU选型与DC/DC/DC、循环扫描五阶段、博途组态及电动机启停自锁梯形图(含考点)
笔记·学习·自动化·制造
问心无愧05135 小时前
[GXYCTF2019]Ping Ping Ping
android·笔记
ACP广源盛139246256735 小时前
项目评估记录:4K 远距离视频 Serdes 传输方案调研,GSV5800@ACP参数与工程问题记录
笔记·硬件架构·音视频·视频·国产芯片
深圳老胡6 小时前
C语言实现C++面向对象程序设计示例
笔记·stm32·单片机·代码规范
yuehuaxin017 小时前
LS8011C 快充协议芯片|SOT‑23‑6L 内置 431,PD3.2 SPR/PPS 适配器物料备选评估调试笔记
笔记·智能家居·适配器模式·智能硬件
巴巴媛6667 小时前
【Debug1】程序死机,while(1)循环,怎么办?
c语言·笔记·stm32·嵌入式硬件·bug