androidx.compose.foundation.relocation

Interfaces

BringIntoViewRequester

Can be used to send bringIntoView requests.

Cmn
BringIntoViewResponder

A parent that can respond to bringChildIntoView requests from its children, and scroll so that the item is visible on screen.

Cmn

Top-level functions summary

Extension functions summary

Modifier
Modifier.bringIntoViewRequester(
    bringIntoViewRequester: BringIntoViewRequester
)

Modifier that can be used to send scrollIntoView requests.

Cmn
Modifier

A parent that can respond to BringIntoViewRequester requests from its children, and scroll so that the item is visible on screen.

Cmn
suspend Unit

Bring this node into bounds by making all the scrollable parents scroll appropriately.

Cmn

Top-level functions

BringIntoViewRequester

fun BringIntoViewRequester(): BringIntoViewRequester

Create an instance of BringIntoViewRequester that can be used with Modifier.bringIntoViewRequester. A child can then call BringIntoViewRequester.bringIntoView to send a request any scrollable parents so that they scroll to bring this item into view.

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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp

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")
        }
    }
}

Extension functions

bringIntoViewRequester

fun Modifier.bringIntoViewRequester(
    bringIntoViewRequester: BringIntoViewRequester
): Modifier

Modifier that can be used to send scrollIntoView requests.

The following example uses a bringIntoViewRequester to bring an item into the parent bounds. The example demonstrates how a composable can ask its parents to scroll so that the component using this modifier is brought into the bounds of all its parents.

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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
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()
        )
    }
}
Parameters
bringIntoViewRequester: BringIntoViewRequester

An instance of BringIntoViewRequester. This hoisted object can be used to send BringIntoViewRequester.scrollIntoView requests to parents of the current composable.

bringIntoViewResponder

fun Modifier.bringIntoViewResponder(responder: BringIntoViewResponder): Modifier

A parent that can respond to BringIntoViewRequester requests from its children, and scroll so that the item is visible on screen. See BringIntoViewResponder for more details about how this mechanism works.

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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
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()
        )
    }
}

scrollIntoView

suspend fun DelegatableNode.scrollIntoView(rect: Rect? = null): Unit

Bring this node into bounds by making all the scrollable parents scroll appropriately.

This method will not return until this request is satisfied or a newer request interrupts it. If this call is interrupted by a newer call, this method will throw a CancellationException.

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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
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()
        )
    }
}
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.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp

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")
        }
    }
}
Parameters
rect: Rect? = null

The rectangle (In local coordinates) that should be brought into view. If you don't specify the coordinates, the coordinates of the Modifier.bringIntoViewRequester() associated with this BringIntoViewRequester will be used.