Created
March 27, 2025 17:51
-
-
Save itsSiddharthGupta/9257e3c90ad507ab344d3b795a761c27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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