BringIntoViewResponder


A parent that can respond to bringChildIntoView requests from its children, and scroll so that the item is visible on screen. To apply a responder to an element, pass it to the bringIntoViewResponder modifier.

When a component calls BringIntoViewRequester.bringIntoView, the nearest BringIntoViewResponder is found, which is responsible for, in order:

  1. Calculating a rectangle that its parent responder should bring into view by returning it from calculateRectForParent.

  2. Performing any scroll or other layout adjustments needed to ensure the requested rectangle is brought into view in bringChildIntoView.

Here is a sample where a composable is brought into view:

import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.focus.focusTarget
import androidx.compose.ui.focus.onFocusChanged

Row(Modifier.horizontalScroll(rememberScrollState())) {
    repeat(100) {
        val bringIntoViewRequester = remember { BringIntoViewRequester() }
        val coroutineScope = rememberCoroutineScope()
        Box(
            Modifier
                // This associates the RelocationRequester with a Composable that wants to be
                // brought into view.
                .bringIntoViewRequester(bringIntoViewRequester)
                .onFocusChanged {
                    if (it.isFocused) {
                        coroutineScope.launch {
                            // This sends a request to all parents that asks them to scroll so
                            // that this item is brought into view.
                            bringIntoViewRequester.bringIntoView()
                        }
                    }
                }
                .focusTarget()
        )
    }
}

Here is a sample where a part of a composable is brought into view:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.border
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect

with(LocalDensity.current) {
    val bringIntoViewRequester = remember { BringIntoViewRequester() }
    val coroutineScope = rememberCoroutineScope()
    Column {
        Box(
            Modifier
                .border(2.dp, Color.Black)
                .size(500f.toDp())
                .horizontalScroll(rememberScrollState())
        ) {
            Canvas(
                Modifier
                    .size(1500f.toDp(), 500f.toDp())
                    // This associates the RelocationRequester with a Composable that wants
                    // to be brought into view.
                    .bringIntoViewRequester(bringIntoViewRequester)
            ) {
                drawCircle(color = Color.Red, radius = 250f, center = Offset(750f, 250f))
            }
        }
        Button(
            onClick = {
                val circleCoordinates = Rect(500f, 0f, 1000f, 500f)
                coroutineScope.launch {
                    // This sends a request to all parents that asks them to scroll so that
                    // the circle is brought into view.
                    bringIntoViewRequester.bringIntoView(circleCoordinates)
                }
            }
        ) {
            Text("Bring circle into View")
        }
    }
}
See also
BringIntoViewRequester

Note: this API is experimental while we optimise the performance and find the right API shape for it

Summary

Public functions

suspend Unit

Bring this specified rectangle into bounds by making this scrollable parent scroll appropriately.

Cmn
Rect

Return the rectangle in this node that should be brought into view by this node's parent, in coordinates relative to this node.

Cmn

Public functions

bringChildIntoView

@ExperimentalFoundationApi
suspend fun bringChildIntoView(localRect: () -> Rect): Unit

Bring this specified rectangle into bounds by making this scrollable parent scroll appropriately.

This method should ensure that only one call is being handled at a time. If you use Compose's Animatable you get this for free, since it will cancel the previous animation when a new one is started while preserving velocity.

Parameters
localRect: () -> Rect

A function returning the rectangle that should be brought into view, relative to this node. This is the same rectangle that will have been passed to calculateRectForParent. The function may return a different value over time, if the bounds of the request change while the request is being processed. If the rectangle cannot be calculated, e.g. because the LayoutCoordinates are not attached, return null.

calculateRectForParent

@ExperimentalFoundationApi
fun calculateRectForParent(localRect: Rect): Rect

Return the rectangle in this node that should be brought into view by this node's parent, in coordinates relative to this node. If this node needs to adjust itself to bring localRect into view, the returned rectangle should be the destination rectangle that localRect will eventually occupy once this node's content is adjusted.

Parameters
localRect: Rect

The rectangle that should be brought into view, relative to this node. This will be the same rectangle passed to bringChildIntoView.

Returns
Rect

The rectangle in this node that should be brought into view itself, relative to this node. If this node needs to scroll to bring localRect into view, the returned rectangle should be the destination rectangle that localRect will eventually occupy, once the scrolling animation is finished.