kuikly-visibility-exposure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseKuikly 曝光与可见性事件
Kuikly Exposure & Visibility Events
核心概念
Core Concepts
Kuikly 提供了一套完整的组件可见性事件系统,用于监听组件在滚动容器或页面中的可见状态变化。四大要素:
- 可见窗口:最近的滚动容器(Scroller/List/WaterfallList)、ModalView 或 Pager
- 可见性状态:四种状态 + 百分比(WILL_APPEAR → DID_APPEAR → WILL_DISAPPEAR → DID_DISAPPEAR)
- 触发时机:滚动偏移变化、子视图布局完成、可见区域 margin 变化、组件被移除
- 应用场景:曝光上报、懒加载、播放控制、可见百分比监听
Kuikly provides a complete Component Visibility Event System for monitoring changes in the visibility state of components within scroll containers or pages. Four core elements:
- Visible Window: The nearest scroll container (Scroller/List/WaterfallList), ModalView or Pager
- Visibility State: Four states + percentage (WILL_APPEAR → DID_APPEAR → WILL_DISAPPEAR → DID_DISAPPEAR)
- Trigger Timing: Scroll offset changes, child view layout completion, visible area margin changes, component removal
- Application Scenarios: Exposure reporting, lazy loading, playback control, visibility percentage monitoring
可见窗口查找规则
Visible Window Search Rules
系统从组件的 parent 开始向上遍历,找到第一个匹配的祖先作为可见窗口:
组件 → parent → ... → ScrollerView(Scroller/List/WaterfallList/PageList)→ 命中
→ ModalView → 命中
→ Pager → 命中(兜底)- 对于 ScrollerView(Scroller/List/WaterfallList):可见性基于列表可见区域计算,会减去滚动偏移量
- 对于 ModalView:可见性基于 Modal 的布局 frame 计算
- 对于 Pager:可见性基于页面的布局 frame 计算
重要:可见性是相对于最近滚动容器的可见区域,而非屏幕位置。若需屏幕位置可见性,如果嵌套滚动容器场景,可使用外层滚动容器的 scroll 事件回调,结合列表偏移量计算节点真实位置。
The system traverses upwards from the component's parent to find the first matching ancestor as the visible window:
Component → parent → ... → ScrollerView(Scroller/List/WaterfallList/PageList)→ Hit
→ ModalView → Hit
→ Pager → Hit (fallback)- For ScrollerView (Scroller/List/WaterfallList): Visibility is calculated based on the list visible area, minus the scroll offset
- For ModalView: Visibility is calculated based on the Modal's layout frame
- For Pager: Visibility is calculated based on the page's layout frame
Important: Visibility is relative to the visible area of the nearest scroll container, not the screen position. If screen position visibility is required, especially in nested scroll container scenarios, you can use the scroll event callback of the outer scroll container and calculate the real position of the node combined with the list offset.
状态机
State Machine
┌──────────────────────────────────────────────┐
│ │
▼ │
DID_DISAPPEAR ──→ WILL_APPEAR ──→ DID_APPEAR ──→ WILL_DISAPPEAR ─┘
(完全不可见) (部分可见) (完全可见) (部分可见)三种空间关系与状态转换:
| 空间关系 | 判定条件 | 状态转换 |
|---|---|---|
| 相离(组件完全在窗口外) | 组件 frame 与窗口无交集 | → WILL_DISAPPEAR → DID_DISAPPEAR |
| 包含(组件完全在窗口内) | 组件 frame 完全在窗口内 | → WILL_APPEAR → DID_APPEAR |
| 相交(组件部分在窗口内) | 组件 frame 与窗口部分重叠 | 从 DID_DISAPPEAR → WILL_APPEAR;从 DID_APPEAR → WILL_DISAPPEAR |
特殊行为:
- 组件被移除(v-if 移除、页面销毁等)时,会自动触发 WILL_DISAPPEAR → DID_DISAPPEAR,并将 percentage 置为 0
- 状态变更是异步的(通过 调度),页面销毁时除外(同步执行)
addNextTickTask
┌──────────────────────────────────────────────┐
│ │
▼ │
DID_DISAPPEAR ──→ WILL_APPEAR ──→ DID_APPEAR ──→ WILL_DISAPPEAR ─┘
(Completely Invisible) (Partially Visible) (Fully Visible) (Partially Visible)Three Spatial Relationships and State Transitions:
| Spatial Relationship | Judgment Condition | State Transition |
|---|---|---|
| Disjoint (Component is completely outside the window) | No intersection between component frame and window | → WILL_DISAPPEAR → DID_DISAPPEAR |
| Contained (Component is completely inside the window) | Component frame is fully within the window | → WILL_APPEAR → DID_APPEAR |
| Intersecting (Component is partially inside the window) | Partial overlap between component frame and window | From DID_DISAPPEAR → WILL_APPEAR; From DID_APPEAR → WILL_DISAPPEAR |
Special Behaviors:
- When a component is removed (removed via v-if, page destroyed, etc.), it will automatically trigger WILL_DISAPPEAR → DID_DISAPPEAR, and set percentage to 0
- State changes are asynchronous (scheduled via ), except when the page is destroyed (executed synchronously)
addNextTickTask
API 速查
API Quick Reference
可见性事件
Visibility Events
| 事件 | 描述 | 回调参数 | import |
|---|---|---|---|
| 组件将要可见(部分进入窗口) | 无 | |
| 组件完全可见(完全在窗口内) | 无 | |
| 组件将要不可见(部分离开窗口) | 无 | |
| 组件完全不可见(完全在窗口外) | 无 | |
| 组件可见百分比变化 | | |
| Event | Description | Callback Parameters | import |
|---|---|---|---|
| Component is about to become visible (partially enters the window) | None | |
| Component is fully visible (completely inside the window) | None | |
| Component is about to become invisible (partially leaves the window) | None | |
| Component is completely invisible (completely outside the window) | None | |
| Component visibility percentage changes | | |
appearPercentage 百分比计算逻辑
appearPercentage Calculation Logic
| 空间关系 | percentage 值 |
|---|---|
| 完全不可见(相离) | 0 |
| 完全可见(包含) | 1 |
| 部分可见(相交) | 纵向列表: |
percentage 值始终被 clamp 到 [0, 1] 范围内。只有当 percentage 发生变化时才会触发回调。
| Spatial Relationship | percentage Value |
|---|---|
| Completely Invisible (Disjoint) | 0 |
| Fully Visible (Contained) | 1 |
| Partially Visible (Intersecting) | Vertical List: |
The percentage value is always clamped to the [0, 1] range. The callback is only triggered when the percentage changes.
Scroller/List/WaterfallList 辅助属性
Scroller/List/WaterfallList Auxiliary Properties
| 属性 | 描述 | 参数类型 | 支持的容器 |
|---|---|---|---|
| 从可见窗口顶部裁掉指定高度 | Float | Scroller、List、WaterfallList |
| 从可见窗口底部裁掉指定高度 | Float | Scroller、List、WaterfallList |
作用原理:缩小列表的"可见性判定窗口"。设置后,可见窗口高度 = 列表高度 - marginTop - marginBottom,子组件 Y 坐标也会减去 marginTop。例如列表高度 500dp,设置和visibleAreaIgnoreTopMargin(60f)后,只有列表中间 360dp 区域内的子组件才会被判定为可见。visibleAreaIgnoreBottomMargin(80f)典型场景:列表顶部/底部有固定遮挡 UI(如悬浮导航栏、半透明蒙层、底部工具栏),被遮挡区域内的子组件虽然在列表坐标系内"可见",但实际上用户看不到,需要从曝光判定中排除。
| Property | Description | Parameter Type | Supported Containers |
|---|---|---|---|
| Cut off the specified height from the top of the visible window | Float | Scroller, List, WaterfallList |
| Cut off the specified height from the bottom of the visible window | Float | Scroller, List, WaterfallList |
Working Principle: Reduce the "visibility judgment window" of the list. After setting, visible window height = list height - marginTop - marginBottom, and the child component Y coordinate will also subtract marginTop. For example, if the list height is 500dp, after settingandvisibleAreaIgnoreTopMargin(60f), only child components within the middle 360dp area of the list will be judged as visible.visibleAreaIgnoreBottomMargin(80f)Typical Scenario: Fixed occluding UI at the top/bottom of the list (such as floating navigation bar, translucent mask, bottom toolbar). Although child components in the occluded area are "visible" in the list coordinate system, users cannot actually see them, so they need to be excluded from exposure judgment.
快速入门
Quick Start
didAppear 曝光上报
didAppear Exposure Reporting
kotlin
import com.tencent.kuikly.core.base.event.didAppear
View {
attr {
size(100f, 100f)
backgroundColor(Color.GREEN)
}
event {
didAppear {
// 组件完全可见,执行曝光上报
}
}
}kotlin
import com.tencent.kuikly.core.base.event.didAppear
View {
attr {
size(100f, 100f)
backgroundColor(Color.GREEN)
}
event {
didAppear {
// Component is fully visible, execute exposure reporting
}
}
}appearPercentage 可见百分比监听
appearPercentage Visibility Percentage Monitoring
kotlin
import com.tencent.kuikly.core.base.event.appearPercentage
View {
attr {
size(100f, 100f)
backgroundColor(Color.GREEN)
}
event {
appearPercentage { percentage01 ->
// percentage01 为 [0,1] 的露出百分比
// 1 表示 100% 可见,0 表示 0% 可见
if (percentage01 >= 0.5f) {
// 超过 50% 可见时执行逻辑
}
}
}
}kotlin
import com.tencent.kuikly.core.base.event.appearPercentage
View {
attr {
size(100f, 100f)
backgroundColor(Color.GREEN)
}
event {
appearPercentage { percentage01 ->
// percentage01 is the visibility percentage in [0,1]
// 1 means 100% visible, 0 means 0% visible
if (percentage01 >= 0.5f) {
// Execute logic when visibility exceeds 50%
}
}
}
}完整生命周期监听
Complete Lifecycle Monitoring
kotlin
import com.tencent.kuikly.core.base.event.willAppear
import com.tencent.kuikly.core.base.event.didAppear
import com.tencent.kuikly.core.base.event.willDisappear
import com.tencent.kuikly.core.base.event.didDisappear
import com.tencent.kuikly.core.base.event.appearPercentage
View {
event {
willAppear {
// 组件将要可见(部分进入窗口)
}
didAppear {
// 组件完全可见 → 曝光上报
}
willDisappear {
// 组件将要不可见(部分离开窗口)
}
didDisappear {
// 组件完全不可见
}
appearPercentage { percentage ->
// 可见百分比变化
}
}
}kotlin
import com.tencent.kuikly.core.base.event.willAppear
import com.tencent.kuikly.core.base.event.didAppear
import com.tencent.kuikly.core.base.event.willDisappear
import com.tencent.kuikly.core.base.event.didDisappear
import com.tencent.kuikly.core.base.event.appearPercentage
View {
event {
willAppear {
// Component is about to become visible (partially enters the window)
}
didAppear {
// Component is fully visible → Execute exposure reporting
}
willDisappear {
// Component is about to become invisible (partially leaves the window)
}
didDisappear {
// Component is completely invisible
}
appearPercentage { percentage ->
// Visibility percentage changes
}
}
}visibleAreaIgnoreMargin 排除遮挡区域
visibleAreaIgnoreMargin Exclude Occluded Areas
kotlin
import com.tencent.kuikly.core.base.event.didAppear
Scroller {
attr {
flex(1f)
// 顶部 60dp 区域内的子组件不参与曝光判定
visibleAreaIgnoreTopMargin(60f)
// 底部 80dp 区域内的子组件不参与曝光判定
visibleAreaIgnoreBottomMargin(80f)
}
View {
attr {
height(120f)
backgroundColor(Color(0xFFE3F2FD))
}
event {
didAppear {
// 只有完全进入中间有效区域(500 - 60 - 80 = 360dp)时才触发
}
}
}
}kotlin
import com.tencent.kuikly.core.base.event.didAppear
Scroller {
attr {
flex(1f)
// Child components in the top 60dp area do not participate in exposure judgment
visibleAreaIgnoreTopMargin(60f)
// Child components in the bottom 80dp area do not participate in exposure judgment
visibleAreaIgnoreBottomMargin(80f)
}
View {
attr {
height(120f)
backgroundColor(Color(0xFFE3F2FD))
}
event {
didAppear {
// Only triggered when fully entering the middle valid area (500 - 60 - 80 = 360dp)
}
}
}
}常见错误与陷阱
Common Mistakes & Pitfalls
| 错误做法 | 正确做法 | 原因 |
|---|---|---|
❌ 根节点使用 | ✅ 使用页面生命周期 | 根节点没有滚动容器作为可见窗口,行为不可预期 |
| ❌ 认为可见性是相对于屏幕位置 | ✅ 可见性是相对于最近滚动容器的可见区域 | 需要屏幕位置请结合 scroll 事件偏移量计算 |
❌ 在 | ✅ 曝光上报用 | |
| ❌ 忘记 import 可见性事件扩展函数 | ✅ 添加对应的 import 语句 | 这些是 |
| Wrong Practice | Correct Practice | Reason |
|---|---|---|
❌ Use | ✅ Use page lifecycle | The root node has no scroll container as visible window, behavior is unpredictable |
| ❌ Assume visibility is relative to screen position | ✅ Visibility is relative to the visible area of the nearest scroll container | For screen position visibility, calculate with scroll event offset |
❌ Directly execute exposure reporting in | ✅ Use | |
| ❌ Forget to import visibility event extension functions | ✅ Add corresponding import statements | These are extension functions of |
完整使用案例
Complete Usage Examples
见 EXAMPLES.md
See EXAMPLES.md