Skip to content

Instantly share code, notes, and snippets.

@itsSiddharthGupta
Created March 27, 2025 17:51
Show Gist options
  • Save itsSiddharthGupta/9257e3c90ad507ab344d3b795a761c27 to your computer and use it in GitHub Desktop.
Save itsSiddharthGupta/9257e3c90ad507ab344d3b795a761c27 to your computer and use it in GitHub Desktop.
private class VisibilityTrackerNode(
var thresholdPercentage: Float,
var onVisibilityChanged: (VisibilityInfo) -> Unit,
) : Modifier.Node(), GlobalPositionAwareModifierNode {
private var previousVisibilityPercentage: Float? = null
// Minimum visibility difference that triggers an update
private val minimumVisibilityDelta = 0.01f
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
// Get information about this composable's position
val boundsInWindow = coordinates.boundsInWindow()
// Get information about the parent window
val parentBounds = coordinates.parentLayoutCoordinates?.boundsInWindow()
if (parentBounds == null) {
// if parent bounds are null, it means that we are not added to the hierarchy, so we are not visible
previousVisibilityPercentage = 0f
return
}
// Calculate visible width
val visibleLeft = max(boundsInWindow.left, parentBounds.left)
val visibleRight = min(boundsInWindow.right, parentBounds.right)
val visibleWidth = max(0f, visibleRight - visibleLeft)
// Calculate visible height
val visibleTop = max(boundsInWindow.top, parentBounds.top)
val visibleBottom = min(boundsInWindow.bottom, parentBounds.bottom)
val visibleHeight = max(0f, visibleBottom - visibleTop)
// Calculate visible area and total area
val visibleArea = visibleWidth * visibleHeight
val totalArea = coordinates.size.width * coordinates.size.height
// Calculate visibility percentage based on area
val visibilityPercentage = (visibleArea / totalArea).coerceIn(0f, 1f)
// Call visibility changed callback only if visibility changed significantly
val visibilityDifference =
previousVisibilityPercentage?.let { previous ->
abs(visibilityPercentage - previous)
} ?: Float.MAX_VALUE
// Update only if changed enough
if (visibilityDifference >= minimumVisibilityDelta) {
onVisibilityChanged(
VisibilityInfo(
isVisible = visibilityPercentage > 0f,
visiblePercentage = visibilityPercentage,
bounds = boundsInWindow,
isAboveThreshold = visibilityPercentage >= thresholdPercentage,
),
)
previousVisibilityPercentage = visibilityPercentage
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment