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
                )
            }
        }
    }
}
相关推荐
Hammer_Hans16 小时前
DFT笔记120
笔记
Ztt66666666616 小时前
月白大竹节壶不露锋芒,竹意藏在嘴把转折里
经验分享·笔记·其他·百度·微信公众平台
XIE39216 小时前
TipKit:开源富文本编辑器套件,一套逻辑,任意风格!
前端·笔记·开源
xieliyu.16 小时前
HTTPS 加密流程深度解析|从 HTTP 痛点到 TLS 握手全过程
网络·笔记·网络协议·计算机网络·http·https
Rsingstarzengjx16 小时前
第二十六章 Linux 蜂鸣器实验笔记
linux·驱动开发·笔记·stm32·嵌入式硬件·stm32mp157
小刘在重生~16 小时前
Django 全套入门笔记|安装、项目创建、ORM、Form、中间件、登录认证
笔记·中间件·django
猎头南楼1 天前
VLA 模型落地端侧:从架构选型到量化部署的工程实践笔记
笔记·架构·大模型
Capricorn19881 天前
日志级幻觉排障:GPT-6 Astra 迈入 AGI 时代,知芽 Notebook Skill 如何以引用校验与零命中诚实弃权解决长文失忆
论文阅读·人工智能·笔记·gpt·agi
疯狂打码的少年1 天前
【数据库技术】多值依赖与第四范式(4NF)
数据库·笔记·算法
tq10861 天前
算法的另一面
笔记