Omkar Amberkar
01/11/2024, 2:08 PMtrue . The composition is in viewport when rendered which is why the value is true in first place and the initial value of it is false.
Expected behavior is that it only gets triggered once right away when its displayed and not twice for the same value true
var isInViewport by remember { mutableStateOf(false) }
Box(modifier.onViewport { inViewport, componentPosition ->
isInViewport = inViewport
currentComponentPosition = componentPosition
})
LaunchedEffect(isInViewport) {
if (isInViewport) {
uim.onDisplay?.invoke(currentComponentPosition)
} else {
uim.onOutOfViewport?.invoke(null)
}
}Pablichjenkov
01/11/2024, 2:23 PMOmkar Amberkar
01/11/2024, 2:37 PMPablichjenkov
01/11/2024, 2:47 PMFabricio Vergara
01/11/2024, 2:51 PMvar lastIsInViewport by rememberSaveable { mutableStateOf(!isInViewport) }
LaunchedEffect(isInViewport) {
if(lastIsInViewport != isInViewport) {
lastIsInViewport = isInViewport
// code
}
}Omkar Amberkar
01/11/2024, 2:52 PMPablichjenkov
01/11/2024, 3:40 PMOmkar Amberkar
01/11/2024, 3:49 PMOmkar Amberkar
01/11/2024, 3:52 PMZach Klippenstein (he/him) [MOD]
01/11/2024, 4:58 PMOmkar Amberkar
01/11/2024, 6:59 PMonViewport is our own custom modifier that looks like below which helps us to get the view's position in the window
onGloballyPositioned { coordinates ->
isInViewport = coordinates.isInViewport()
val (x: Int, y: Int, width: Int, height: Int) = when {
isInViewport -> with(coordinates.positionInRoot()) {
listOf(x.toInt(), y.toInt(), coordinates.size.width, coordinates.size.height)
}
else -> listOf(0, 0, 0, 0)
}
componentPosition = ComponentPosition(
topLeftX = x,
topLeftY = y,
width = width,
height = height
)
}Zach Klippenstein (he/him) [MOD]
01/11/2024, 7:09 PMonGloballyPositioned happens even after the layout passOmkar Amberkar
01/11/2024, 7:12 PMfun Modifier.onViewport(
onDisplayedInViewport: (Boolean, ComponentPosition) -> Unit,
): Modifier = composed {
var isInViewport by remember { mutableStateOf(false) }
var isDisplayed by remember { mutableStateOf(false) }
var componentPosition by remember { mutableStateOf(ComponentPosition.Default) }
LaunchedEffect(isInViewport, isDisplayed, onDisplayedInViewport) {
if (!isInViewport) {
isDisplayed = false
onDisplayedInViewport(isDisplayed, componentPosition)
} else if (!isDisplayed) {
isDisplayed = true
onDisplayedInViewport(isDisplayed, componentPosition)
}
}
onGloballyPositioned { coordinates ->
isInViewport = coordinates.isInViewport()
val (x: Int, y: Int, width: Int, height: Int) = when {
isInViewport -> with(coordinates.positionInRoot()) {
listOf(x.toInt(), y.toInt(), coordinates.size.width, coordinates.size.height)
}
else -> listOf(0, 0, 0, 0)
}
componentPosition = ComponentPosition(
topLeftX = x,
topLeftY = y,
width = width,
height = height
)
}
}
for a mofidier inside a column hosted by lazyColumn
as such
onViewport { inViewport, componentPosition ->
isInViewport = inViewport
currentComponentPosition = componentPosition
}
which results in LaunchedEffect called twice in the below case
var isInViewport by remember { mutableStateOf(false) }
Box(Modifier.
onViewport { inViewport, componentPosition ->
isInViewport = inViewport
currentComponentPosition = componentPosition
}
)
LaunchedEffect(isInViewport) {
if (isInViewport) {
uim.onDisplay?.invoke(currentComponentPosition)
} else {
uim.onOutOfViewport?.invoke(null)
}
}Omkar Amberkar
01/11/2024, 7:13 PMZach Klippenstein (he/him) [MOD]
01/11/2024, 8:18 PMisInViewport=false on the first composition. Then you’ll do the first layout pass, get the onGloballyPositioned callback, which may set isInViewport to true, which will cause a recomposition on the next frame where you’ll see the new value. If the component is not in view immediately, then it shouldn’t recompose again until it comes into view.Zach Klippenstein (he/him) [MOD]
01/11/2024, 8:20 PMLaunchedEffect(uim) {
snapshotFlow { isInViewport }.collect { isInViewport ->
if (isInViewport) {
…
}
}louiscad
01/17/2024, 3:59 PMsnapshotFlow instead of a LaunchedEffect key?Zach Klippenstein (he/him) [MOD]
01/17/2024, 4:10 PMlouiscad
01/17/2024, 4:19 PM