SubspaceModifier

interface SubspaceModifier

Known direct subclasses
SubspaceModifier.Companion

The companion object SubspaceModifier is the empty, default, or starter SubspaceModifier that contains no SubspaceModifierNodeElements.

SubspaceModifierNodeElement

Modifier elements manage an instance of a particular SubspaceModifier.Node implementation.


An ordered, immutable collection of subspace modifier elements that decorate or add behavior to Subspace Compose elements.

Based on androidx.compose.ui.Modifier

Summary

Nested types

The companion object SubspaceModifier is the empty, default, or starter SubspaceModifier that contains no SubspaceModifierNodeElements.

The longer-lived object that is created for each SubspaceModifierNodeElement applied to a SubspaceLayout

Public companion functions

infix SubspaceModifier
open String

Public functions

open Boolean

Returns true if predicate returns true for all SubspaceModifierNodeElements in this SubspaceModifier or if this SubspaceModifier contains no Elements.

open Boolean

Returns true if predicate returns true for any SubspaceModifierNodeElement in this SubspaceModifier.

open R
<R : Any?> foldIn(
    initial: R,
    operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R
)

Accumulates a value starting with initial and applying operation to the current value and each SubspaceModifierNodeElement from outside in.

open R
<R : Any?> foldOut(
    initial: R,
    operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R
)

Accumulates a value starting with initial and applying operation to the current value and each SubspaceModifierNodeElement from inside out.

open infix SubspaceModifier

Concatenates this modifier with another.

Extension functions

SubspaceModifier
SubspaceModifier.alpha(alpha: @FloatRange(from = 0.0, to = 1.0) Float)

Sets the opacity of this element (and its children) to a value between 0..1.

SubspaceModifier
SubspaceModifier.aspectRatio(
    ratio: @FloatRange(from = 0.0, fromInclusive = false) Float,
    matchHeightConstraintsFirst: Boolean
)

Attempts to size the content to match a specified aspect ratio by trying to match one of the incoming constraints in the following order: VolumeConstraints.maxWidth, VolumeConstraints.maxHeight, VolumeConstraints.minWidth, VolumeConstraints.minHeight if matchHeightConstraintsFirst is false (which is the default), or VolumeConstraints.maxHeight, VolumeConstraints.maxWidth, VolumeConstraints.minHeight, VolumeConstraints.minWidth if matchHeightConstraintsFirst is true.

SubspaceModifier

A SubspaceModifier that forces the content to remain upright, aligned with gravity by isolating the element's yaw by cancelling parent pitch and roll.

SubspaceModifier

Creates a node that allows changing how the wrapped element is measured and laid out.

SubspaceModifier
SubspaceModifier.movable(
    enabled: Boolean,
    stickyPose: Boolean,
    scaleWithDistance: Boolean,
    onMoveStart: ((SpatialMoveEvent) -> Unit)?,
    onMoveEnd: ((SpatialMoveEvent) -> Unit)?,
    onMove: ((SpatialMoveEvent) -> Boolean)?
)

When the movable modifier is present and enabled, draggable UI controls will be shown that allow the user to move the element in 3D space.

SubspaceModifier

Offset the content by (x dp, y dp, z dp) without considering layout direction.

SubspaceModifier
SubspaceModifier.offset(x: Dp, y: Dp, z: Dp)

Offset the content by (x dp, y dp, z dp).

SubspaceModifier

Invoke onGloballyPositioned with the SubspaceLayoutCoordinates of the element when the global position or the orientation of the content may have changed.

SubspaceModifier
SubspaceModifier.onSizeChanged(
    onSizeChanged: (size: IntVolumeSize) -> Unit
)

Invokes onSizeChanged with the IntVolumeSize of the element when its size changes.

SubspaceModifier
SubspaceModifier.absolutePadding(
    left: Dp,
    top: Dp,
    right: Dp,
    bottom: Dp,
    front: Dp,
    back: Dp
)

Apply additional space along each edge of the content in Dp: left, top, right, bottom, front and back.

SubspaceModifier

Apply all dp of additional space along each edge of the content, left, top, right, bottom, front, and back.

SubspaceModifier
SubspaceModifier.padding(horizontal: Dp, vertical: Dp, depth: Dp)

Apply horizontal dp space along the left and right edges of the content, vertical dp space along the top and bottom edges, and depth dp space along front and back edged.

SubspaceModifier
SubspaceModifier.padding(
    start: Dp,
    top: Dp,
    end: Dp,
    bottom: Dp,
    front: Dp,
    back: Dp
)

Apply additional space along each edge of the content in Dp: start, top, end, bottom, front and back.

SubspaceModifier

When present, this modifier defines how the pointer icon will be displayed when the spatial pointer hovers over an element.

SubspaceModifier
SubspaceModifier.resizable(
    enabled: Boolean,
    minimumSize: DpVolumeSize,
    maximumSize: DpVolumeSize,
    maintainAspectRatio: Boolean,
    onResizeStart: (IntVolumeSize) -> Unit,
    onResizeUpdate: (IntVolumeSize) -> Unit,
    onResizeEnd: (IntVolumeSize) -> Boolean
)

When the resizable modifier is present and enabled, draggable UI controls will be shown that allow the user to resize the element in 3D space.

SubspaceModifier

This function is deprecated. SubspaceModifier.rotate() with no arguments does nothing.

SubspaceModifier

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element.

SubspaceModifier
SubspaceModifier.rotate(axisAngle: Vector3, rotation: Float)

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element.

SubspaceModifier
SubspaceModifier.rotate(pitch: Float, yaw: Float, roll: Float)

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element.

SubspaceModifier

A SubspaceModifier that continuously rotates content so that it faces the user at all times.

SubspaceModifier
SubspaceModifier.scale(
    scale: @FloatRange(from = 0.0, fromInclusive = false) Float
)

Scale the contents of the composable by the scale factor along horizontal, vertical, and depth axes.

SubspaceModifier

Add semantics key/value pairs to the layout node, for use in testing, accessibility, etc.

SubspaceModifier

Declare the preferred size of the content to be exactly depth dp along the z dimension.

SubspaceModifier
SubspaceModifier.depthIn(min: Dp, max: Dp)

Constrain the depth of the content to be between mindp and maxdp as permitted by the incoming measurement constraints.

SubspaceModifier
SubspaceModifier.fillMaxDepth(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float
)

Have the content fill (possibly only partially) the VolumeConstraints.maxDepth of the incoming measurement constraints, by setting the minimum depth and the maximum depth to be equal to the maximum depth multiplied by fraction.

SubspaceModifier
SubspaceModifier.fillMaxHeight(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float
)

Have the content fill (possibly only partially) the VolumeConstraints.maxHeight of the incoming measurement constraints, by setting the minimum height and the maximum height to be equal to the maximum height multiplied by fraction.

SubspaceModifier
SubspaceModifier.fillMaxSize(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float
)

Have the content fill (possibly only partially) the VolumeConstraints.maxWidth, VolumeConstraints.maxHeight, and VolumeConstraints.maxDepth of the incoming measurement constraints.

SubspaceModifier
SubspaceModifier.fillMaxWidth(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float
)

Have the content fill (possibly only partially) the VolumeConstraints.maxWidth of the incoming measurement constraints, by setting the minimum width and the maximum width to be equal to the maximum width multiplied by fraction.

SubspaceModifier

Declare the preferred size of the content to be exactly height dp along the y dimension.

SubspaceModifier

Constrain the height of the content to be between mindp and maxdp as permitted by the incoming measurement constraints.

SubspaceModifier

Declare the size of the content to be exactly depth dp along the z dimension, disregarding the incoming VolumeConstraints.

SubspaceModifier

Constrain the depth of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

SubspaceModifier

Declare the size of the content to be exactly height dp along the y dimension, disregarding the incoming VolumeConstraints.

SubspaceModifier

Constrain the height of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

SubspaceModifier

Declare the size of the content to be exactly a size dp cube, disregarding the incoming VolumeConstraints.

SubspaceModifier

Declare the size of the content to be exactly size in each of the three dimensions, disregarding the incoming VolumeConstraints.

SubspaceModifier
SubspaceModifier.requiredSize(width: Dp, height: Dp, depth: Dp)

Declare the size of the content to be exactly width, height, and depth in each of the three dimensions, disregarding the incoming VolumeConstraints.

SubspaceModifier
SubspaceModifier.requiredSizeIn(
    minWidth: Dp,
    maxWidth: Dp,
    minHeight: Dp,
    maxHeight: Dp,
    minDepth: Dp,
    maxDepth: Dp
)

Constrain the size of the content to be between min and max dp, disregarding the incoming measurement VolumeConstraints.

SubspaceModifier

Declare the size of the content to be exactly width dp along the x dimension, disregarding the incoming VolumeConstraints.

SubspaceModifier

Constrain the width of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

SubspaceModifier

Declare the preferred size of the content to be exactly a size dp cube.

SubspaceModifier

Declare the preferred size of the content to be exactly size in each of the three dimensions.

SubspaceModifier
SubspaceModifier.size(width: Dp, height: Dp, depth: Dp)

Declare the preferred size of the content to be exactly width dp along the x dimensions, height dp along the y dimensions, and depth dp along the z dimension.

SubspaceModifier
SubspaceModifier.sizeIn(
    minWidth: Dp,
    maxWidth: Dp,
    minHeight: Dp,
    maxHeight: Dp,
    minDepth: Dp,
    maxDepth: Dp
)

Constrain the size of the content to be between min and max dp as permitted by the incoming measurement constraints.

SubspaceModifier

Declare the preferred size of the content to be exactly width dp along the x dimension.

SubspaceModifier
SubspaceModifier.widthIn(min: Dp, max: Dp)

Constrain the width of the content to be between mindp and maxdp as permitted by the incoming measurement constraints.

SubspaceModifier

Applies a tag to allow modified element to be found in tests.

Public companion functions

toString

open fun toString(): String

Public functions

all

Added in 1.0.0-alpha13
open fun all(
    predicate: (SubspaceModifierNodeElement<SubspaceModifier.Node>) -> Boolean
): Boolean

Returns true if predicate returns true for all SubspaceModifierNodeElements in this SubspaceModifier or if this SubspaceModifier contains no Elements.

Parameters
predicate: (SubspaceModifierNodeElement<SubspaceModifier.Node>) -> Boolean

condition to evaluate for each element.

any

Added in 1.0.0-alpha13
open fun any(
    predicate: (SubspaceModifierNodeElement<SubspaceModifier.Node>) -> Boolean
): Boolean

Returns true if predicate returns true for any SubspaceModifierNodeElement in this SubspaceModifier.

Parameters
predicate: (SubspaceModifierNodeElement<SubspaceModifier.Node>) -> Boolean

condition to evaluate for each element.

foldIn

Added in 1.0.0-alpha13
open fun <R : Any?> foldIn(
    initial: R,
    operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R
): R

Accumulates a value starting with initial and applying operation to the current value and each SubspaceModifierNodeElement from outside in.

Parameters
initial: R

initial value for the accumulation.

operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R

function to apply to the current accumulated value and the next element.

foldOut

Added in 1.0.0-alpha13
open fun <R : Any?> foldOut(
    initial: R,
    operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R
): R

Accumulates a value starting with initial and applying operation to the current value and each SubspaceModifierNodeElement from inside out.

Parameters
initial: R

initial value for the accumulation.

operation: (SubspaceModifierNodeElement<SubspaceModifier.Node>, R) -> R

function to apply to the next element and the current accumulated value.

then

Added in 1.0.0-alpha13
open infix fun then(other: SubspaceModifier): SubspaceModifier

Concatenates this modifier with another.

Returns a SubspaceModifier representing this modifier followed by other in sequence.

Parameters
other: SubspaceModifier

SubspaceModifier to concatenate to this one.

Extension functions

SubspaceModifier.alpha

fun SubspaceModifier.alpha(alpha: @FloatRange(from = 0.0, to = 1.0) Float): SubspaceModifier

Sets the opacity of this element (and its children) to a value between 0..1. An alpha value of 0.0f means fully transparent while a value of 1.0f is completely opaque. Elements with semi-transparent alpha values (> 0.0 but < 1.0f) will be rendered using alpha-blending.

Parameters
alpha: @FloatRange(from = 0.0, to = 1.0) Float

the opacity of this element (and its children). Must be a value between 0 and 1, inclusive. Values < 0 or > 1 will be clamped.

SubspaceModifier.aspectRatio

fun SubspaceModifier.aspectRatio(
    ratio: @FloatRange(from = 0.0, fromInclusive = false) Float,
    matchHeightConstraintsFirst: Boolean = false
): SubspaceModifier

Attempts to size the content to match a specified aspect ratio by trying to match one of the incoming constraints in the following order: VolumeConstraints.maxWidth, VolumeConstraints.maxHeight, VolumeConstraints.minWidth, VolumeConstraints.minHeight if matchHeightConstraintsFirst is false (which is the default), or VolumeConstraints.maxHeight, VolumeConstraints.maxWidth, VolumeConstraints.minHeight, VolumeConstraints.minWidth if matchHeightConstraintsFirst is true. The size in the other dimension is determined by the aspect ratio. The combinations will be tried in this order until one non-empty is found to satisfy the constraints. If no valid size is obtained this way, it means that there is no non-empty size satisfying both the constraints and the aspect ratio, so the constraints will not be respected and the content will be sized such that the VolumeConstraints.maxWidth or VolumeConstraints.maxHeight is matched (depending on matchHeightConstraintsFirst). Note that this modifier constrains the ratio between the content's width and height only. The depth dimension is not affected or constrained by this aspect ratio modifier.

Example usage:

SpatialPanel(SubspaceModifier.width(100.dp).aspectRatio(16f / 9f)) {
Text(text = "Inner Composable Content")
}
Parameters
ratio: @FloatRange(from = 0.0, fromInclusive = false) Float

the desired width/height positive ratio

matchHeightConstraintsFirst: Boolean = false

if true, height constraints will be matched before width constraints and used to calculate the resulting size according to ratio

SubspaceModifier.gravityAligned

fun SubspaceModifier.gravityAligned(): SubspaceModifier

A SubspaceModifier that forces the content to remain upright, aligned with gravity by isolating the element's yaw by cancelling parent pitch and roll.

This modifier calculates the necessary counter-rotation to ignore the pitch and roll of its parent entity's total world transformation. It only affects the rotation and not the translation. This is useful for UI elements like labels or billboards that should always stay level, regardless of the orientation of the object they are attached to. It effectively isolates the yaw (rotation around the vertical Y-axis).

SubspaceModifier.layout

fun SubspaceModifier.layout(
    measure: SubspaceMeasureScope.(SubspaceMeasurable, VolumeConstraints) -> SubspaceMeasureResult
): SubspaceModifier

Creates a node that allows changing how the wrapped element is measured and laid out.

Parameters
measure: SubspaceMeasureScope.(SubspaceMeasurable, VolumeConstraints) -> SubspaceMeasureResult

function that defines the measurement and placement logic.

SubspaceModifier.movable

fun SubspaceModifier.movable(
    enabled: Boolean = true,
    stickyPose: Boolean = false,
    scaleWithDistance: Boolean = true,
    onMoveStart: ((SpatialMoveEvent) -> Unit)? = null,
    onMoveEnd: ((SpatialMoveEvent) -> Unit)? = null,
    onMove: ((SpatialMoveEvent) -> Boolean)? = null
): SubspaceModifier

When the movable modifier is present and enabled, draggable UI controls will be shown that allow the user to move the element in 3D space.

There are some limitations that should be considered when using this modifier: 1) the draggable UI controls of nested composables using the movable modifier may conflict with each other, 2) when attaching multiple movable modifiers that handle movement internally, the movement effect will be compounded.

import androidx.compose.material3.Text
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.movable

SpatialPanel(modifier = SubspaceModifier.movable()) { Text("The user can move me around!") }
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.dp
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.movable
import androidx.xr.compose.subspace.layout.offset
import androidx.xr.compose.subspace.layout.rotate
import androidx.xr.compose.unit.Meter.Companion.meters
import androidx.xr.runtime.math.Quaternion

var offsetX by remember { mutableStateOf(0.dp) }
var offsetY by remember { mutableStateOf(0.dp) }
var offsetZ by remember { mutableStateOf(0.dp) }
var rotation by remember { mutableStateOf(Quaternion.Identity) }

SpatialPanel(
    modifier =
        SubspaceModifier.movable {
                offsetX = it.pose.translation.x.meters.toDp()
                offsetY = it.pose.translation.y.meters.toDp()
                offsetZ = it.pose.translation.z.meters.toDp()
                rotation = it.pose.rotation

                true // return true to prevent default behavior
            }
            .offset(x = offsetX, y = offsetY, z = offsetZ)
            .rotate(rotation)
) {
    Text("The user can move me around!")
}
Parameters
enabled: Boolean = true

true if this composable should be movable.

stickyPose: Boolean = false

if enabled, the user specified position will be retained when the modifier is disabled or removed.

scaleWithDistance: Boolean = true

true if this composable should scale in size when moved in depth. When this scaleWithDistance is enabled, the subspace element moved will grow or shrink. It will also maintain any explicit scale that it had before movement.

onMoveStart: ((SpatialMoveEvent) -> Unit)? = null

a callback to process the start of a move event. This will only be called if enabled is true.

onMoveEnd: ((SpatialMoveEvent) -> Unit)? = null

a callback to process the end of a move event. This will only be called if enabled is true.

onMove: ((SpatialMoveEvent) -> Boolean)? = null

a callback to process the pose change during movement, with translation in pixels. This will only be called if enabled is true. If the callback returns false the default behavior of moving this composable's subspace hierarchy will be executed. If it returns true, it is the responsibility of the callback to process the event.

See also
SpatialMoveEvent

.

SubspaceModifier.absoluteOffset

fun SubspaceModifier.absoluteOffset(x: Dp = 0.dp, y: Dp = 0.dp, z: Dp = 0.dp): SubspaceModifier

Offset the content by (x dp, y dp, z dp) without considering layout direction. The offsets can be positive as well as non-positive.

This modifier will not consider layout direction when calculating the position of the content: a positive x offset will always move the content to the right. For a modifier that considers the layout direction when applying the offset, see offset.

Parameters
x: Dp = 0.dp

horizontal offset in Dp.

y: Dp = 0.dp

vertical offset in Dp.

z: Dp = 0.dp

depth offset in Dp.

See also
offset

SubspaceModifier.offset

fun SubspaceModifier.offset(x: Dp = 0.dp, y: Dp = 0.dp, z: Dp = 0.dp): SubspaceModifier

Offset the content by (x dp, y dp, z dp). The offsets can be positive as well as non-positive.

This modifier will automatically adjust the horizontal offset according to the layout direction: when the layout direction is LTR, positive x offsets will move the content to the right and when the layout direction is RTL, positive x offsets will move the content to the left. For a modifier that offsets without considering layout direction, see absoluteOffset.

Parameters
x: Dp = 0.dp

horizontal offset in Dp.

y: Dp = 0.dp

vertical offset in Dp.

z: Dp = 0.dp

depth offset in Dp.

See also
absoluteOffset

SubspaceModifier.onGloballyPositioned

fun SubspaceModifier.onGloballyPositioned(
    onGloballyPositioned: (SubspaceLayoutCoordinates) -> Unit
): SubspaceModifier

Invoke onGloballyPositioned with the SubspaceLayoutCoordinates of the element when the global position or the orientation of the content may have changed. Note that it will be called after a composition when the coordinates are finalized.

This callback executes after composition once the final coordinates are determined. It will be invoked at least once when the SubspaceLayoutCoordinates become available and subsequently whenever the composable's transform (position, rotation, scale) is updated relative to the subspace's origin.

The callback information will be relative to its subspace. For instance, When a nested subspace is moved by the global subspace its Pose will reflect its position in the nested subspace. Its position value will not be updated despite moving locations in the Global Subspace.

Parameters
onGloballyPositioned: (SubspaceLayoutCoordinates) -> Unit

callback to be invoked with the updated SubspaceLayoutCoordinates.

SubspaceModifier.onSizeChanged

fun SubspaceModifier.onSizeChanged(
    onSizeChanged: (size: IntVolumeSize) -> Unit
): SubspaceModifier

Invokes onSizeChanged with the IntVolumeSize of the element when its size changes.

This callback is executed after the layout pass when the SubspaceComposable's size is finalized. It will be invoked at least once when the size becomes available and subsequently whenever the size changes.

For observing changes to position or orientation in addition to size, use SubspaceModifier.onGloballyPositioned instead.

Parameters
onSizeChanged: (size: IntVolumeSize) -> Unit

The callback that is invoked when the size changes. The IntVolumeSize parameter represents the new size of the layout in pixels.

SubspaceModifier.absolutePadding

fun SubspaceModifier.absolutePadding(
    left: Dp = 0.dp,
    top: Dp = 0.dp,
    right: Dp = 0.dp,
    bottom: Dp = 0.dp,
    front: Dp = 0.dp,
    back: Dp = 0.dp
): SubspaceModifier

Apply additional space along each edge of the content in Dp: left, top, right, bottom, front and back. Padding is applied before content measurement and takes precedence; content may only be as large as the remaining space. To apply relative padding with layout direction, see padding.

Negative padding is not permitted — it will cause IllegalArgumentException.

Parameters
left: Dp = 0.dp

The amount of space at the left edge of the content.

top: Dp = 0.dp

The amount of space at the top edge of the content.

right: Dp = 0.dp

The amount of space at the right edge of the content.

bottom: Dp = 0.dp

The amount of space at the bottom edge of the content.

front: Dp = 0.dp

The amount of space at the front edge of the content.

back: Dp = 0.dp

The amount of space at the back edge of the content.

See also
padding

SubspaceModifier.padding

fun SubspaceModifier.padding(all: Dp): SubspaceModifier

Apply all dp of additional space along each edge of the content, left, top, right, bottom, front, and back. Padding is applied before content measurement and takes precedence; content may only be as large as the remaining space.

Negative padding is not permitted — it will cause IllegalArgumentException. See padding

Parameters
all: Dp

The amount of space at each edge of the content.

SubspaceModifier.padding

fun SubspaceModifier.padding(
    horizontal: Dp = 0.dp,
    vertical: Dp = 0.dp,
    depth: Dp = 0.dp
): SubspaceModifier

Apply horizontal dp space along the left and right edges of the content, vertical dp space along the top and bottom edges, and depth dp space along front and back edged. Padding is applied before content measurement and takes precedence; content may only be as large as the remaining space.

Negative padding is not permitted — it will cause IllegalArgumentException. See padding

Parameters
horizontal: Dp = 0.dp

The amount of space at the left and right edges of the content.

vertical: Dp = 0.dp

The amount of space at the top and bottom edges of the content.

depth: Dp = 0.dp

The amount of space at the front and back edges of the content.

SubspaceModifier.padding

fun SubspaceModifier.padding(
    start: Dp = 0.dp,
    top: Dp = 0.dp,
    end: Dp = 0.dp,
    bottom: Dp = 0.dp,
    front: Dp = 0.dp,
    back: Dp = 0.dp
): SubspaceModifier

Apply additional space along each edge of the content in Dp: start, top, end, bottom, front and back. The start and end edges will be determined by the current LayoutDirection. Padding is applied before content measurement and takes precedence; content may only be as large as the remaining space. To not consider the layout direction when applying the padding, see absolutePadding.

Negative padding is not permitted — it will cause IllegalArgumentException.

Parameters
start: Dp = 0.dp

The amount of space at the start edge of the content. Start edge is left if the layout direction is LTR, or right for RTL.

top: Dp = 0.dp

The amount of space at the top edge of the content.

end: Dp = 0.dp

The amount of space at the end edge of the content. End edge is right if the layout direction is LTR, or left for RTL.

bottom: Dp = 0.dp

The amount of space at the bottom edge of the content.

front: Dp = 0.dp

The amount of space at the front edge of the content.

back: Dp = 0.dp

The amount of space at the back edge of the content.

See also
absolutePadding

SubspaceModifier.pointerHoverIcon

fun SubspaceModifier.pointerHoverIcon(icon: SpatialPointerIcon): SubspaceModifier

When present, this modifier defines how the pointer icon will be displayed when the spatial pointer hovers over an element. Any child elements will inherit the pointer icon setting that this modifier defines for their parent element upon hovering.

Parameters
icon: SpatialPointerIcon

The SpatialPointerIcon to be displayed on hover.

Returns
SubspaceModifier

A SubspaceModifier that includes the hover icon behavior.

SubspaceModifier.resizable

fun SubspaceModifier.resizable(
    enabled: Boolean = true,
    minimumSize: DpVolumeSize = DpVolumeSize.Zero,
    maximumSize: DpVolumeSize = DpVolumeSize(Dp.Infinity, Dp.Infinity, Dp.Infinity),
    maintainAspectRatio: Boolean = false,
    onResizeStart: (IntVolumeSize) -> Unit = {},
    onResizeUpdate: (IntVolumeSize) -> Unit = {},
    onResizeEnd: (IntVolumeSize) -> Boolean = { false }
): SubspaceModifier

When the resizable modifier is present and enabled, draggable UI controls will be shown that allow the user to resize the element in 3D space.

Parameters
enabled: Boolean = true

Whether resizing is enabled for this object. If false, the object cannot be resized. When resizing behavior is handled by the API, changing the enabled state of the modifier does not clear the user resize state; whereas, removing the modifier will reset the user resize state, causing the object to revert to its layout size. Defaults to true.

minimumSize: DpVolumeSize = DpVolumeSize.Zero

The minimum allowable size for the object, represented by a DpVolumeSize. The object cannot be scaled down beyond these dimensions. Defaults to DpVolumeSize.Zero.

maximumSize: DpVolumeSize = DpVolumeSize(Dp.Infinity, Dp.Infinity, Dp.Infinity)

The maximum allowable size for the object, represented by a DpVolumeSize. The object cannot be scaled up beyond these dimensions. Defaults to a DpVolumeSize with all dimensions set to Dp.Infinity, meaning no upper limit by default.

maintainAspectRatio: Boolean = false

If true, the object's aspect ratio (proportions) will be preserved during resizing. If false, individual dimensions can be changed independently. Defaults to false.

onResizeStart: (IntVolumeSize) -> Unit = {}

A callback to be called when the resize event starts.

onResizeUpdate: (IntVolumeSize) -> Unit = {}

A callback to be called when the size changes during a resize event.

onResizeEnd: (IntVolumeSize) -> Boolean = { false }

A callback to be called when the object's size changes, after a resize event has ended. It receives an IntVolumeSize representing the new size. Returning true from this callback indicates that the developer intends to handle the size change, and the API should not resize the object. Returning false indicates that the developer will not handle the size change, and the API should proceed with changing the size of the object itself. By default, if onResizeEnd is not provided, the API will change the size of the object.

SubspaceModifier.rotate

fun SubspaceModifier.rotate(): SubspaceModifier

This overload is provided to prevent rotate from being called with no arguments.

SubspaceModifier.rotate

fun SubspaceModifier.rotate(quaternion: Quaternion): SubspaceModifier

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element. The rotation is directly specified by the provided Quaternion. The Quaternion values are specified as x,y,z,w. Where w is the rotation of the unit vector, in radians.

Parameters
quaternion: Quaternion

Quaternion describing the rotation.

SubspaceModifier.rotate

fun SubspaceModifier.rotate(axisAngle: Vector3, rotation: Float): SubspaceModifier

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element. The rotation is defined by a Vector3 and a rotation angle in degrees. The axis angle will be normalized during construction. The rotation will be applied to the unit vector representing the axisAngle.

Parameters
axisAngle: Vector3

Vector representing the axis of rotation.

rotation: Float

Degrees of rotation.

SubspaceModifier.rotate

fun SubspaceModifier.rotate(pitch: Float = 0.0f, yaw: Float = 0.0f, roll: Float = 0.0f): SubspaceModifier

Rotate a subspace element (i.e. Panel) in space in regard to the center of the element. Parameter rotation angles are specified in degrees. The rotations are applied with the order pitch, then yaw, then roll. If no values are provided, no rotation is applied.

Parameters
pitch: Float = 0.0f

Rotation around the x-axis. Defaults to 0.0f. The x-axis is the axis width is measured on.

yaw: Float = 0.0f

Rotation around the y-axis. Defaults to 0.0f. The y-axis is the axis height is measured on.

roll: Float = 0.0f

Rotation around the z-axis. Defaults to 0.0f. The z-axis is the axis depth is measured on.

SubspaceModifier.rotateToLookAtUser

fun SubspaceModifier.rotateToLookAtUser(upDirection: Vector3 = Vector3.Up): SubspaceModifier

A SubspaceModifier that continuously rotates content so that it faces the user at all times.

A user of this API should configure the activity's Session object with DeviceTrackingMode.SPATIAL_LAST_KNOWN which requires android.permission.HEAD_TRACKING Android permission be granted by the calling application. session.configure( config = session.config.copy(deviceTracking = DeviceTrackingMode.SPATIAL_LAST_KNOWN) )

This modifier might not work as expected when used on content within a androidx.xr.compose.spatial.FollowingSubspace.

The preceding rotate modifiers will be disregarded because this modifier will override them. But the rotate after the rotateToLookAtUser modifier will be respected.

To achieve a "billboard" effect—where the content rotates to face the user on the Y-axis while remaining upright and aligned with gravity—combine this with gravityAligned.

import androidx.compose.material3.Text
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.gravityAligned
import androidx.xr.compose.subspace.layout.rotate
import androidx.xr.compose.subspace.layout.rotateToLookAtUser

Subspace {
    SpatialPanel(modifier = SubspaceModifier.rotateToLookAtUser().gravityAligned()) {
        Text("I always face you and stay upright!")
    }
}
import androidx.compose.material3.Text
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.rotate
import androidx.xr.compose.subspace.layout.rotateToLookAtUser
import androidx.xr.runtime.math.Vector3

Subspace {
    SpatialPanel(
        modifier =
            SubspaceModifier.rotateToLookAtUser(
                upDirection = Vector3(0f, 1f, 2f)
            ) // A slightly tilted "up" reference
    ) {
        Text("I have a custom 'Up' vector.")
    }
}
import androidx.compose.material3.Text
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.SpatialBox
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.rotate
import androidx.xr.compose.subspace.layout.rotateToLookAtUser
import androidx.xr.runtime.math.Quaternion

val parentRotation = Quaternion.fromEulerAngles(pitch = 40f, yaw = 30f, roll = 20f)

Subspace {
    SpatialBox(SubspaceModifier.rotate(parentRotation)) {
        // This panel will rotate to face the user regardless of where
        // the parent SpatialBox is placed in the ActivitySpace.
        SpatialPanel(modifier = SubspaceModifier.rotateToLookAtUser()) {
            Text("I'm inside a SpatialBox, but I still see you!")
        }
    }
}
Parameters
upDirection: Vector3 = Vector3.Up

Defines the reference "up" direction for the content's orientation. Pointing the content's forward vector at the user leaves the rotation around that axis (roll) undefined; this vector resolves that ambiguity. The default is Vector3.Up, which corresponds to the up direction of the ActivitySpace.

SubspaceModifier.scale

fun SubspaceModifier.scale(
    scale: @FloatRange(from = 0.0, fromInclusive = false) Float
): SubspaceModifier

Scale the contents of the composable by the scale factor along horizontal, vertical, and depth axes. Scaling does not change the measured size of the composable content during layout. Measured size of androidx.xr.compose.subspace.SubspaceComposable elements can be controlled using size Modifiers. Scale factor should be a positive number.

Parameters
scale: @FloatRange(from = 0.0, fromInclusive = false) Float

Multiplier to scale content along vertical, horizontal, depth axes.

SubspaceModifier.semantics

fun SubspaceModifier.semantics(properties: SemanticsPropertyReceiver.() -> Unit): SubspaceModifier

Add semantics key/value pairs to the layout node, for use in testing, accessibility, etc.

Parameters
properties: SemanticsPropertyReceiver.() -> Unit

Builder block where the semantics properties are defined.

SubspaceModifier.depth

fun SubspaceModifier.depth(depth: Dp): SubspaceModifier

Declare the preferred size of the content to be exactly depth dp along the z dimension. Panels have 0 depth and ignore this modifier.

Parameters
depth: Dp

preferred depth in Dp.

SubspaceModifier.depthIn

fun SubspaceModifier.depthIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified): SubspaceModifier

Constrain the depth of the content to be between mindp and maxdp as permitted by the incoming measurement constraints. If the incoming constraints are more restrictive the requested size will obey the incoming constraints and attempt to be as close as possible to the preferred size.

Parameters
min: Dp = Dp.Unspecified

The minimum depth.

max: Dp = Dp.Unspecified

The maximum depth.

SubspaceModifier.fillMaxDepth

fun SubspaceModifier.fillMaxDepth(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f
): SubspaceModifier

Have the content fill (possibly only partially) the VolumeConstraints.maxDepth of the incoming measurement constraints, by setting the minimum depth and the maximum depth to be equal to the maximum depth multiplied by fraction. Note that, by default, the fraction is 1, so the modifier will make the content fill the whole available depth. If the incoming maximum depth is VolumeConstraints.INFINITY this modifier will have no effect.

Parameters
fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f

The fraction of the maximum height to use, between 0 and 1, inclusive.

SubspaceModifier.fillMaxHeight

fun SubspaceModifier.fillMaxHeight(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f
): SubspaceModifier

Have the content fill (possibly only partially) the VolumeConstraints.maxHeight of the incoming measurement constraints, by setting the minimum height and the maximum height to be equal to the maximum height multiplied by fraction. Note that, by default, the fraction is 1, so the modifier will make the content fill the whole available height. If the incoming maximum height is VolumeConstraints.INFINITY this modifier will have no effect.

Parameters
fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f

The fraction of the maximum height to use, between 0 and 1, inclusive.

SubspaceModifier.fillMaxSize

fun SubspaceModifier.fillMaxSize(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f
): SubspaceModifier

Have the content fill (possibly only partially) the VolumeConstraints.maxWidth, VolumeConstraints.maxHeight, and VolumeConstraints.maxDepth of the incoming measurement constraints. See SubspaceModifier.fillMaxWidth, SubspaceModifier.fillMaxHeight, and SubspaceModifier.fillMaxDepth for details. Note that, by default, the fraction is 1, so the modifier will make the content fill the whole available space. If the incoming maximum width or height or depth is VolumeConstraints.INFINITY this modifier will have no effect in that dimension.

Parameters
fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f

The fraction of the maximum size to use, between 0 and 1, inclusive.

SubspaceModifier.fillMaxWidth

fun SubspaceModifier.fillMaxWidth(
    fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f
): SubspaceModifier

Have the content fill (possibly only partially) the VolumeConstraints.maxWidth of the incoming measurement constraints, by setting the minimum width and the maximum width to be equal to the maximum width multiplied by fraction. Note that, by default, the fraction is 1, so the modifier will make the content fill the whole available width. If the incoming maximum width is VolumeConstraints.INFINITY this modifier will have no effect.

Parameters
fraction: @FloatRange(from = 0.0, to = 1.0) Float = 1.0f

The fraction of the maximum width to use, between 0 and 1, inclusive.

SubspaceModifier.height

fun SubspaceModifier.height(height: Dp): SubspaceModifier

Declare the preferred size of the content to be exactly height dp along the y dimension.

Parameters
height: Dp

preferred height in Dp.

SubspaceModifier.heightIn

fun SubspaceModifier.heightIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified): SubspaceModifier

Constrain the height of the content to be between mindp and maxdp as permitted by the incoming measurement constraints. If the incoming constraints are more restrictive the requested size will obey the incoming constraints and attempt to be as close as possible to the preferred size.

Parameters
min: Dp = Dp.Unspecified

The minimum height.

max: Dp = Dp.Unspecified

The maximum height.

SubspaceModifier.requiredDepth

fun SubspaceModifier.requiredDepth(depth: Dp): SubspaceModifier

Declare the size of the content to be exactly depth dp along the z dimension, disregarding the incoming VolumeConstraints.

This is in contrast to SubspaceModifier.depth, which respects the parent's constraints. requiredDepth will ignore the minDepth and maxDepth from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds.

Parameters
depth: Dp

required depth in Dp.

SubspaceModifier.requiredDepthIn

fun SubspaceModifier.requiredDepthIn(
    min: Dp = Dp.Unspecified,
    max: Dp = Dp.Unspecified
): SubspaceModifier

Constrain the depth of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

This is in contrast to SubspaceModifier.depthIn, which respects the parent's constraints. requiredDepthIn will ignore the minDepth and maxDepth from the incoming constraints.

Parameters
min: Dp = Dp.Unspecified

The minimum depth.

max: Dp = Dp.Unspecified

The maximum depth.

SubspaceModifier.requiredHeight

fun SubspaceModifier.requiredHeight(height: Dp): SubspaceModifier

Declare the size of the content to be exactly height dp along the y dimension, disregarding the incoming VolumeConstraints.

This is in contrast to SubspaceModifier.height, which respects the parent's constraints. requiredHeight will ignore the minHeight and maxHeight from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds.

Parameters
height: Dp

required height in Dp.

SubspaceModifier.requiredHeightIn

fun SubspaceModifier.requiredHeightIn(
    min: Dp = Dp.Unspecified,
    max: Dp = Dp.Unspecified
): SubspaceModifier

Constrain the height of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

This is in contrast to SubspaceModifier.heightIn, which respects the parent's constraints. requiredHeightIn will ignore the minHeight and maxHeight from the incoming constraints.

Parameters
min: Dp = Dp.Unspecified

The minimum height.

max: Dp = Dp.Unspecified

The maximum height.

SubspaceModifier.requiredSize

fun SubspaceModifier.requiredSize(size: Dp): SubspaceModifier

Declare the size of the content to be exactly a size dp cube, disregarding the incoming VolumeConstraints. When applied to a Panel, the size will be a size dp square instead.

This is in contrast to SubspaceModifier.size, which respects the parent's constraints. requiredSize will ignore all min and max constraints from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds.

Parameters
size: Dp

required size in Dp for all dimensions.

SubspaceModifier.requiredSize

fun SubspaceModifier.requiredSize(size: DpVolumeSize): SubspaceModifier

Declare the size of the content to be exactly size in each of the three dimensions, disregarding the incoming VolumeConstraints. Panels have 0 depth and ignore the z-component of this modifier.

This is in contrast to SubspaceModifier.size, which respects the parent's constraints. requiredSize will ignore all min and max constraints from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds. The parent will then determine how to handle the overflow.

Parameters
size: DpVolumeSize

required volume size as a DpVolumeSize.

SubspaceModifier.requiredSize

fun SubspaceModifier.requiredSize(
    width: Dp = Dp.Unspecified,
    height: Dp = Dp.Unspecified,
    depth: Dp = Dp.Unspecified
): SubspaceModifier

Declare the size of the content to be exactly width, height, and depth in each of the three dimensions, disregarding the incoming VolumeConstraints. Panels have 0 depth and ignore the z-component of this modifier.

This is in contrast to SubspaceModifier.size, which respects the parent's constraints. requiredSize will ignore all min and max constraints from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds. The parent will then determine how to handle the overflow.

Parameters
width: Dp = Dp.Unspecified

required width in Dp.

height: Dp = Dp.Unspecified

required height in Dp.

depth: Dp = Dp.Unspecified

required depth in Dp.

SubspaceModifier.requiredSizeIn

fun SubspaceModifier.requiredSizeIn(
    minWidth: Dp = Dp.Unspecified,
    maxWidth: Dp = Dp.Unspecified,
    minHeight: Dp = Dp.Unspecified,
    maxHeight: Dp = Dp.Unspecified,
    minDepth: Dp = Dp.Unspecified,
    maxDepth: Dp = Dp.Unspecified
): SubspaceModifier

Constrain the size of the content to be between min and max dp, disregarding the incoming measurement VolumeConstraints.

This is in contrast to SubspaceModifier.sizeIn, which respects the parent's constraints. requiredSizeIn will ignore the min and max constraints from the incoming constraints, which can be useful for sizing an element to a specific range even if it exceeds the parent's bounds.

Parameters
minWidth: Dp = Dp.Unspecified

The minimum width.

maxWidth: Dp = Dp.Unspecified

The maximum width.

minHeight: Dp = Dp.Unspecified

The minimum height.

maxHeight: Dp = Dp.Unspecified

The maximum height.

minDepth: Dp = Dp.Unspecified

The minimum depth.

maxDepth: Dp = Dp.Unspecified

The maximum depth.

SubspaceModifier.requiredWidth

fun SubspaceModifier.requiredWidth(width: Dp): SubspaceModifier

Declare the size of the content to be exactly width dp along the x dimension, disregarding the incoming VolumeConstraints.

This is in contrast to SubspaceModifier.width, which respects the parent's constraints. requiredWidth will ignore the minWidth and maxWidth from the incoming constraints, which can be useful for sizing an element to a specific value even if it exceeds the parent's bounds.

Parameters
width: Dp

required width in Dp.

SubspaceModifier.requiredWidthIn

fun SubspaceModifier.requiredWidthIn(
    min: Dp = Dp.Unspecified,
    max: Dp = Dp.Unspecified
): SubspaceModifier

Constrain the width of the content to be between min dp and max dp, disregarding the incoming measurement VolumeConstraints.

This is in contrast to SubspaceModifier.widthIn, which respects the parent's constraints. requiredWidthIn will ignore the minWidth and maxWidth from the incoming constraints.

Parameters
min: Dp = Dp.Unspecified

The minimum width.

max: Dp = Dp.Unspecified

The maximum width.

SubspaceModifier.size

fun SubspaceModifier.size(size: Dp): SubspaceModifier

Declare the preferred size of the content to be exactly a size dp cube. When applied to a Panel, the preferred size will be a size dp square instead.

Parameters
size: Dp

preferred size in Dp for all dimensions.

SubspaceModifier.size

fun SubspaceModifier.size(size: DpVolumeSize): SubspaceModifier

Declare the preferred size of the content to be exactly size in each of the three dimensions. Panels have 0 depth and ignore the z-component of this modifier.

Parameters
size: DpVolumeSize

preferred volume size as a DpVolumeSize.

SubspaceModifier.size

fun SubspaceModifier.size(
    width: Dp = Dp.Unspecified,
    height: Dp = Dp.Unspecified,
    depth: Dp = Dp.Unspecified
): SubspaceModifier

Declare the preferred size of the content to be exactly width dp along the x dimensions, height dp along the y dimensions, and depth dp along the z dimension.

Parameters
width: Dp = Dp.Unspecified

preferred width in Dp.

height: Dp = Dp.Unspecified

preferred height in Dp.

depth: Dp = Dp.Unspecified

preferred depth in Dp.

SubspaceModifier.sizeIn

fun SubspaceModifier.sizeIn(
    minWidth: Dp = Dp.Unspecified,
    maxWidth: Dp = Dp.Unspecified,
    minHeight: Dp = Dp.Unspecified,
    maxHeight: Dp = Dp.Unspecified,
    minDepth: Dp = Dp.Unspecified,
    maxDepth: Dp = Dp.Unspecified
): SubspaceModifier

Constrain the size of the content to be between min and max dp as permitted by the incoming measurement constraints. If the incoming constraints are more restrictive the requested size will obey the incoming constraints and attempt to be as close as possible to the preferred size.

Parameters
minWidth: Dp = Dp.Unspecified

The minimum width.

maxWidth: Dp = Dp.Unspecified

The maximum width.

minHeight: Dp = Dp.Unspecified

The minimum height.

maxHeight: Dp = Dp.Unspecified

The maximum height.

minDepth: Dp = Dp.Unspecified

The minimum depth.

maxDepth: Dp = Dp.Unspecified

The maximum depth.

SubspaceModifier.width

fun SubspaceModifier.width(width: Dp): SubspaceModifier

Declare the preferred size of the content to be exactly width dp along the x dimension.

Parameters
width: Dp

preferred width in Dp.

SubspaceModifier.widthIn

fun SubspaceModifier.widthIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified): SubspaceModifier

Constrain the width of the content to be between mindp and maxdp as permitted by the incoming measurement constraints. If the incoming constraints are more restrictive the requested size will obey the incoming constraints and attempt to be as close as possible to the preferred size.

Parameters
min: Dp = Dp.Unspecified

The minimum width.

max: Dp = Dp.Unspecified

The maximum width.

SubspaceModifier.testTag

fun SubspaceModifier.testTag(tag: String): SubspaceModifier

Applies a tag to allow modified element to be found in tests.

This is a convenience method for a semantics that sets SemanticsPropertyReceiver.testTag.

Parameters
tag: String

String used to identify the modified element in tests.