https://kotlinlang.org logo
#compose
Title
# compose
v

Valentin Gusselnikov

04/14/2022, 1:29 PM
Hi! How can I detect if Composable element is visible on the screen or vice versa, without too much calculations? I want to hide the top
Image
if the
Button
(which is placed at the end) is not visible and user have to scroll for it. Root Composable is
ConstraintLayout
🙏 1
I came up with something like this (stolen from here):
Copy code
fun Modifier.onNotVisible(onNotVisible: () -> Unit): Modifier = composed {
    val view = LocalView.current
    var isVisible: Boolean? by remember { mutableStateOf(null) }

    if (isVisible == true) {
        LaunchedEffect(isVisible) {
            onNotVisible()
        }
    }

    onGloballyPositioned { coordinates ->
        isVisible = coordinates.isCompletelyVisible(view)
    }
}

fun LayoutCoordinates.isCompletelyVisible(view: View): Boolean {
    if (!isAttached) return false
    // Window relative bounds of our compose root view that are visible on the screen
    val globalRootRect = android.graphics.Rect()
    if (!view.getGlobalVisibleRect(globalRootRect)) {
        // we aren't visible at all.
        return false
    }
    val bounds = boundsInWindow()
    // Make sure we are completely in bounds.
    return <http://bounds.top|bounds.top> >= <http://globalRootRect.top|globalRootRect.top> &&
            bounds.left >= globalRootRect.left &&
            bounds.right <= globalRootRect.right &&
            bounds.bottom <= globalRootRect.bottom
}
Which is used like this (most of the content is omitted, so it's easier to read):
Copy code
@Composable
private fun Content(
    info: Model
) {
    var showImage by remember { mutableStateOf(true) }
    
    if (showImage)
        Image(
            painter = painterResource(id = R.drawable.img),
            contentDescription = null,
            modifier = Modifier
                .constrainAs(imageRef) {
                    width = Dimension.fillToConstraints
                    top.linkTo(<http://parent.top|parent.top>, 16.dp)
                    centerHorizontallyTo(parent)
                }
        )
        
    Button(
        onClick = {},
        modifier = Modifier
            .height(56.dp)
            .constrainAs(buttonInviteRef) {
                width = Dimension.fillToConstraints
                linkTo(
                    start = guideLineStartRef,
                    top = boxPointsRef.bottom,
                    end = guideLineEndRef,
                    bottom = parent.bottom,
                    verticalBias = 1f,
                    topMargin = 40.dp,
                    bottomMargin = 16.dp
                )
            }
            .onNotVisible {
                showImage = false
            }
    )
}
But I think there's gotta be a better way to do this without a custom
Layout
...
😮 1
1656 Views