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
                )
            }
        }
    }
}
相关推荐
Peter-OK13 分钟前
PostgreSQL学习笔记(入门-进阶-精通说明)
笔记·学习·postgresql
成都蜀味缘餐饮技术培训学校2 小时前
手撕烤兔技术培训实战指南,秘制腌料配方比例与调制手法
大数据·经验分享·笔记·其他·微信公众平台
希和20273 小时前
免费AI视频生成工具汇总(国内优先,适合做漫剧、短视频,Obsidian笔记版)
人工智能·笔记·音视频
蒸蒸yyyyzwd5 小时前
秋招学习笔记 day109
笔记·八股
只愿云淡风清7 小时前
正则表达式学习笔记 02:基础语法
笔记·学习·正则表达式
希和202718 小时前
考研英语阅读词汇笔记|城市野径、抄近道步道(非正式小路)
笔记·考研
一个人旅程~20 小时前
关于imac27inch因改短用户名导致混合硬盘和系统崩溃的问题分析与故障解决
经验分享·笔记·macos·新浪微博
心祭丫丫21 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
派大猩猩_1 天前
Obsidian 笔记怎么同步多端:Nutstore Sync 大笔记库同步测评
笔记·obsidian·obsidian插件·obsidian同步
叼烟扛炮1 天前
Linux 学习笔记(五十):网络层——IP 协议、子网划分与 NAT 魔法
linux·笔记·学习