androidx.wear.compose.foundation

Interfaces

ArcPaddingValues

Apply additional space along each edge of the content in Dp.

CurvedAlignment
CurvedDirection
CurvedModifier

An ordered, immutable, collection of modifier elements that work with curved components, in a polar coordinate space.

ReduceMotion

ReduceMotion provides a means for callers to determine whether an app should turn off animations and screen movement.

RevealScope
ScrollInfoProvider

An interface for providing scroll information for different scrollable containers, such lists.

Classes

AnchorType

Specifies how components will be laid down with respect to the anchor.

CurvedAlignment.Angular

How to lay down components when they have a smaller sweep than their container.

CurvedAlignment.Radial

How to lay down components when they are thinner than the container.

CurvedDirection.Angular

The direction in which components are laid out on a curvedRow or CurvedLayout

CurvedDirection.Radial

The direction in which components are lay down on a curvedColumn

CurvedScope

Layout scope used for curved containers.

CurvedTextStyle

Styling configuration for a curved text.

ExpandableState

State of the Expandable composables.

ExpandableStateMapping

A class that maps from keys of the given type to ExpandableState.

RevealActionType

Different values which can trigger the state change from one RevealValue to another.

RevealState

A class to keep track of the state of the composable.

RevealValue

Different values that determine the state of the SwipeToReveal composable, reflected in RevealState.currentValue.

SwipeDirection

Different values SwipeToReveal composable can reveal the actions from.

SwipeToDismissBoxState

State for BasicSwipeToDismissBox.

Objects

CurvedModifier.Companion

The companion object CurvedModifier is the empty, default, or starter CurvedModifier that contains no Elements.

ExpandableItemsDefaults

Contains the default values used by Expandable components.

SwipeToDismissBoxDefaults

Contains defaults for BasicSwipeToDismissBox.

Annotations

Enums

SwipeToDismissKeys

Keys used to persistent state in BasicSwipeToDismissBox.

SwipeToDismissValue

States used as targets for the anchor points for swipe-to-dismiss.

Top-level functions summary

Unit

Use as part of a focus-requiring component to register a callback to be notified when the focus state changes.

Unit

Use as part of a focus-requiring component to register a callback to automatically request focus when this component is active.

ArcPaddingValues

Apply all dp of additional space along each edge of the content.

ArcPaddingValues
ArcPaddingValues(radial: Dp, angular: Dp)

Apply radial dp of additional space on the edges towards and away from the center, and angular dp before and after the component.

ArcPaddingValues
ArcPaddingValues(outer: Dp, inner: Dp, before: Dp, after: Dp)

Apply additional space along each edge of the content in Dp.

Unit
@Composable
BasicSwipeToDismissBox(
    state: SwipeToDismissBoxState,
    modifier: Modifier,
    backgroundKey: Any,
    contentKey: Any,
    userSwipeEnabled: Boolean,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)

BasicSwipeToDismissBox that handles the swipe-to-dismiss gesture.

Unit
@Composable
BasicSwipeToDismissBox(
    onDismissed: () -> Unit,
    modifier: Modifier,
    state: SwipeToDismissBoxState,
    backgroundKey: Any,
    contentKey: Any,
    userSwipeEnabled: Boolean,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)

BasicSwipeToDismissBox that handles the swipe-to-dismiss gesture.

Unit
@Composable
CurvedLayout(
    modifier: Modifier,
    anchor: Float,
    anchorType: AnchorType,
    radialAlignment: CurvedAlignment.Radial?,
    angularDirection: CurvedDirection.Angular,
    contentBuilder: CurvedScope.() -> Unit
)

A layout composable that places its children in an arc, rotating them as needed.

Unit
@Composable
HierarchicalFocusCoordinator(
    requiresFocus: () -> Boolean,
    content: @Composable () -> Unit
)

Coordinates focus for any composables in content and determines which composable will get focus.

ScrollInfoProvider

Function for creating a ScrollInfoProvider from a LazyListState, for use with LazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

ScrollInfoProvider

Function for creating a ScrollInfoProvider from a PagerState, for use with HorizontalPager and VerticalPager

ScrollInfoProvider

Function for creating a ScrollInfoProvider from a ScalingLazyListState, for use with ScalingLazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

ScrollInfoProvider

Function for creating a ScrollInfoProvider from a ScrollState, for use with Column - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

ScrollInfoProvider

Function for creating a ScrollInfoProvider from a TransformingLazyColumnState, for use with TransformingLazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

Unit
@Composable
SwipeToReveal(
    primaryAction: @Composable RevealScope.() -> Unit,
    modifier: Modifier,
    onFullSwipe: () -> Unit,
    state: RevealState,
    secondaryAction: (@Composable RevealScope.() -> Unit)?,
    undoAction: (@Composable RevealScope.() -> Unit)?,
    content: @Composable () -> Unit
)

A composable that can be used to add extra actions to a composable (up to two) which will be revealed when the original composable is swiped to the left.

Map<RevealValueFloat>
createAnchors(
    coveredAnchor: Float,
    revealingAnchor: Float,
    revealedAnchor: Float,
    swipeDirection: SwipeDirection
)

Creates the required anchors to which the top content can be swiped, to reveal the actions.

FocusRequester

Creates, remembers and returns a new FocusRequester, that will have .requestFocus called when the enclosing HierarchicalFocusCoordinator becomes active.

ExpandableState
@Composable
rememberExpandableState(
    initiallyExpanded: Boolean,
    expandAnimationSpec: AnimationSpec<Float>,
    collapseAnimationSpec: AnimationSpec<Float>
)

Create and remember an ExpandableState

ExpandableStateMapping<T>
@Composable
@ExperimentalWearFoundationApi
<T : Any?> rememberExpandableStateMapping(
    initiallyExpanded: (key) -> Boolean,
    expandAnimationSpec: AnimationSpec<Float>,
    collapseAnimationSpec: AnimationSpec<Float>
)

Create and remember a mapping from keys to ExpandableStates ExpandableStates can be requested by key, and we will created with the parameters given here when a mapping didn't exist before.

RevealState
@Composable
rememberRevealState(
    initialValue: RevealValue,
    animationSpec: AnimationSpec<Float>,
    confirmValueChange: (RevealValue) -> Boolean,
    positionalThreshold: Density.(totalDistance: Float) -> Float,
    anchors: Map<RevealValueFloat>
)

Create and remember a RevealState.

SwipeToDismissBoxState
@Composable
rememberSwipeToDismissBoxState(
    animationSpec: AnimationSpec<Float>,
    confirmStateChange: (SwipeToDismissValue) -> Boolean
)

Create a SwipeToDismissBoxState and remember it.

Extension functions summary

CurvedModifier
CurvedModifier.angularGradientBackground(
    vararg colorStops: Pair<FloatColor>,
    cap: StrokeCap
)

Specifies a sweep gradient background for a curved element.

CurvedModifier

Specifies a sweep gradient background for a curved element.

CurvedModifier

Specify the sweep (angular size) for the content.

CurvedModifier

Specify the sweep (arc length) for the content in Dp.

CurvedModifier

Specified a solid background for a curved element.

Unit
CurvedScope.basicCurvedText(
    text: String,
    modifier: CurvedModifier,
    angularDirection: CurvedDirection.Angular?,
    overflow: TextOverflow,
    style: @Composable () -> CurvedTextStyle
)

basicCurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen).

Unit
CurvedScope.basicCurvedText(
    text: String,
    style: CurvedTextStyle,
    modifier: CurvedModifier,
    angularDirection: CurvedDirection.Angular?,
    overflow: TextOverflow
)

basicCurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen).

Unit
CurvedScope.curvedBox(
    modifier: CurvedModifier,
    radialAlignment: CurvedAlignment.Radial?,
    angularAlignment: CurvedAlignment.Angular?,
    contentBuilder: CurvedScope.() -> Unit
)

A layout composable that places its children on top of each other and on an arc.

Unit
CurvedScope.curvedColumn(
    modifier: CurvedModifier,
    radialDirection: CurvedDirection.Radial?,
    angularAlignment: CurvedAlignment.Angular?,
    contentBuilder: CurvedScope.() -> Unit
)

A curved layout composable that places its children stacked as part of an arc (the first child will be the outermost).

Unit
CurvedScope.curvedComposable(
    modifier: CurvedModifier,
    radialAlignment: CurvedAlignment.Radial,
    rotationLocked: Boolean,
    content: @Composable BoxScope.() -> Unit
)

Component that allows normal composables to be part of a CurvedLayout.

Unit
CurvedScope.curvedRow(
    modifier: CurvedModifier,
    radialAlignment: CurvedAlignment.Radial?,
    angularDirection: CurvedDirection.Angular?,
    contentBuilder: CurvedScope.() -> Unit
)

A layout composable that places its children in an arc, rotating them as needed.

Modifier
Modifier.edgeSwipeToDismiss(
    swipeToDismissBoxState: SwipeToDismissBoxState,
    edgeWidth: Dp
)

Limits swipe to dismiss to be active from the edge of the viewport only.

Unit
ScalingLazyListScope.expandableButton(
    state: ExpandableState,
    key: Any?,
    content: @Composable () -> Unit
)

Adds a single item, for the button that controls expandable item(s).

Unit
ScalingLazyListScope.expandableItem(
    state: ExpandableState,
    key: Any?,
    content: @Composable (expanded: Boolean) -> Unit
)

Adds a single item, that will be expanded/collapsed according to the ExpandableState.

Unit
ScalingLazyListScope.expandableItems(
    state: ExpandableState,
    count: Int,
    key: ((index: Int) -> Any)?,
    itemContent: @Composable BoxScope.(index: Int) -> Unit
)

Adds a series of items, that will be expanded/collapsed according to the ExpandableState

CurvedModifier

Apply all dp space around the component.

CurvedModifier

Apply additional space along the edges of the content.

CurvedModifier
CurvedModifier.padding(radial: Dp, angular: Dp)

Apply angular dp space before and after the component, and radial dp space to the outer and inner edges.

CurvedModifier
CurvedModifier.padding(outer: Dp, inner: Dp, before: Dp, after: Dp)

Apply additional space along the edges of the content.

CurvedModifier
CurvedModifier.parentDataModifier(modifyParentData: (Any?) -> Any?)

A CurvedModifier that provides data to the parent layout.

CurvedModifier
CurvedModifier.radialGradientBackground(
    vararg colorStops: Pair<FloatColor>,
    cap: StrokeCap
)

Specifies a radial gradient background for a curved element.

CurvedModifier

Specifies a radial gradient background for a curved element.

CurvedModifier

Specify the radialSize (thickness) for the content.

CurvedModifier
CurvedModifier.size(
    sweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float,
    thickness: Dp
)

Specify the dimensions (sweep and thickness) for the content.

CurvedModifier
CurvedModifier.sizeIn(
    minSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float,
    maxSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float,
    minThickness: Dp,
    maxThickness: Dp
)

Specify the dimensions of the content to be restricted between the given bounds.

CurvedModifier
CurvedModifier.weight(
    weight: @FloatRange(from = 0.0, fromInclusive = false) Float
)

Size the element's proportional to its weight relative to other weighted sibling elements in the container (this will be the height in a curvedColumn and the width in a curvedRow).

Top-level properties summary

ProvidableCompositionLocal<ReduceMotion>

CompositionLocal for global reduce-motion setting, which turns off animations and screen movements.

ProvidableCompositionLocal<Color>

CompositionLocal containing the background scrim color of BasicSwipeToDismissBox.

ProvidableCompositionLocal<Color>

CompositionLocal containing the content scrim color of BasicSwipeToDismissBox.

Top-level functions

ActiveFocusListener

@Composable
fun ActiveFocusListener(onFocusChanged: CoroutineScope.(Boolean) -> Unit): Unit

Use as part of a focus-requiring component to register a callback to be notified when the focus state changes.

Parameters
onFocusChanged: CoroutineScope.(Boolean) -> Unit

callback to be invoked when the focus state changes, the parameter is the new state (if true, we are becoming active and should request focus).

ActiveFocusRequester

@Composable
fun ActiveFocusRequester(focusRequester: FocusRequester): Unit

Use as part of a focus-requiring component to register a callback to automatically request focus when this component is active. Note that this may call requestFocus in the provided FocusRequester, so that focusRequester should be used in a .focusRequester modifier on a Composable that is part of the composition.

Parameters
focusRequester: FocusRequester

The associated FocusRequester to request focus on.

fun ArcPaddingValues(all: Dp): ArcPaddingValues

Apply all dp of additional space along each edge of the content.

fun ArcPaddingValues(radial: Dp = 0.dp, angular: Dp = 0.dp): ArcPaddingValues

Apply radial dp of additional space on the edges towards and away from the center, and angular dp before and after the component.

fun ArcPaddingValues(outer: Dp = 0.dp, inner: Dp = 0.dp, before: Dp = 0.dp, after: Dp = 0.dp): ArcPaddingValues

Apply additional space along each edge of the content in Dp. Note that that all dimensions are applied to a concrete edge, indepenend on layout direction and curved layout direction.

Parameters
outer: Dp = 0.dp

Padding in the outward direction from the center of the CurvedLayout

inner: Dp = 0.dp

Padding in the inwards direction towards the center of the CurvedLayout

before: Dp = 0.dp

Padding added before the component, if it was draw clockwise.

after: Dp = 0.dp

Padding added after the component, if it was draw clockwise.

BasicSwipeToDismissBox

@Composable
fun BasicSwipeToDismissBox(
    state: SwipeToDismissBoxState,
    modifier: Modifier = Modifier,
    backgroundKey: Any = SwipeToDismissKeys.Background,
    contentKey: Any = SwipeToDismissKeys.Content,
    userSwipeEnabled: Boolean = true,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit

BasicSwipeToDismissBox that handles the swipe-to-dismiss gesture. Takes a single slot for the background (only displayed during the swipe gesture) and the foreground content.

Example of a BasicSwipeToDismissBox with stateful composables:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.BasicSwipeToDismissBox
import androidx.wear.compose.foundation.SwipeToDismissValue
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.SplitToggleChip
import androidx.wear.compose.material.Text
import androidx.wear.compose.material.ToggleChipDefaults

// State for managing a 2-level navigation hierarchy between
// MainScreen and ItemScreen composables.
// Alternatively, use SwipeDismissableNavHost from wear.compose.navigation.
var showMainScreen by remember { mutableStateOf(true) }
val saveableStateHolder = rememberSaveableStateHolder()

// Swipe gesture dismisses ItemScreen to return to MainScreen.
val state = rememberSwipeToDismissBoxState()
LaunchedEffect(state.currentValue) {
    if (state.currentValue == SwipeToDismissValue.Dismissed) {
        state.snapTo(SwipeToDismissValue.Default)
        showMainScreen = !showMainScreen
    }
}

// Hierarchy is ListScreen -> ItemScreen, so we show ListScreen as the background behind
// the ItemScreen, otherwise there's no background to show.
BasicSwipeToDismissBox(
    state = state,
    userSwipeEnabled = !showMainScreen,
    backgroundKey = if (!showMainScreen) "MainKey" else "Background",
    contentKey = if (showMainScreen) "MainKey" else "ItemKey",
) { isBackground ->
    if (isBackground || showMainScreen) {
        // Best practice would be to use State Hoisting and leave this composable stateless.
        // Here, we want to support MainScreen being shown from different destinations
        // (either in the foreground or in the background during swiping) - that can be achieved
        // using SaveableStateHolder and rememberSaveable as shown below.
        saveableStateHolder.SaveableStateProvider(
            key = "MainKey",
            content = {
                // Composable that maintains its own state
                // and can be shown in foreground or background.
                val checked = rememberSaveable { mutableStateOf(true) }
                Column(
                    modifier =
                        Modifier.fillMaxSize().padding(horizontal = 8.dp, vertical = 8.dp),
                    verticalArrangement =
                        Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
                ) {
                    SplitToggleChip(
                        checked = checked.value,
                        label = { Text("Item details") },
                        modifier = Modifier.height(40.dp),
                        onCheckedChange = { v -> checked.value = v },
                        onClick = { showMainScreen = false },
                        toggleControl = {
                            Icon(
                                imageVector =
                                    ToggleChipDefaults.checkboxIcon(checked = checked.value),
                                contentDescription = null,
                            )
                        }
                    )
                }
            }
        )
    } else {
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
            Text("Show details here...", color = MaterialTheme.colors.onPrimary)
            Text("Swipe right to dismiss", color = MaterialTheme.colors.onPrimary)
        }
    }
}

Example of using Modifier.edgeSwipeToDismiss with BasicSwipeToDismissBox

import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.BasicSwipeToDismissBox
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text

val state = rememberSwipeToDismissBoxState()

// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
BasicSwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    val horizontalScrollState = rememberScrollState(0)
    if (isBackground) {
        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
        Box(modifier = Modifier.fillMaxSize()) {
            Text(
                modifier =
                    Modifier.align(Alignment.Center)
                        .edgeSwipeToDismiss(state)
                        .horizontalScroll(horizontalScrollState),
                text =
                    "This text can be scrolled horizontally - to dismiss, swipe " +
                        "right from the left edge of the screen (called Edge Swiping)",
            )
        }
    }
}

For more information, see the Swipe to dismiss guide.

To set the custom values of background scrim color and content scrim color, provide the composition locals - LocalSwipeToDismissBackgroundScrimColor and LocalSwipeToDismissContentScrimColor.

Parameters
state: SwipeToDismissBoxState

State containing information about ongoing swipe or animation.

modifier: Modifier = Modifier

Modifier for this component.

backgroundKey: Any = SwipeToDismissKeys.Background

key which identifies the content currently composed in the content block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when BasicSwipeToDismissBox is used for the navigation). This allows remembered state to be correctly moved between background and foreground.

contentKey: Any = SwipeToDismissKeys.Content

key which identifies the content currently composed in the content block when isBackground == false. See backgroundKey.

userSwipeEnabled: Boolean = true

Whether the swipe gesture is enabled. (e.g. when there is no background screen, set userSwipeEnabled = false)

content: @Composable BoxScope.(isBackground: Boolean) -> Unit

Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold.

BasicSwipeToDismissBox

@Composable
fun BasicSwipeToDismissBox(
    onDismissed: () -> Unit,
    modifier: Modifier = Modifier,
    state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState(),
    backgroundKey: Any = SwipeToDismissKeys.Background,
    contentKey: Any = SwipeToDismissKeys.Content,
    userSwipeEnabled: Boolean = true,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit

BasicSwipeToDismissBox that handles the swipe-to-dismiss gesture. This overload takes an onDismissed parameter which is used to execute a command when the swipe to dismiss has completed, such as navigating to another screen.

Example of a simple SwipeToDismissBox:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.BasicSwipeToDismissBox
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text

val state = rememberSwipeToDismissBoxState()
BasicSwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    if (isBackground) {
        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
            Text("Swipe right to dismiss", color = MaterialTheme.colors.onPrimary)
        }
    }
}

Example of using Modifier.edgeSwipeToDismiss with BasicSwipeToDismissBox

import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.BasicSwipeToDismissBox
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text

val state = rememberSwipeToDismissBoxState()

// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
BasicSwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    val horizontalScrollState = rememberScrollState(0)
    if (isBackground) {
        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
        Box(modifier = Modifier.fillMaxSize()) {
            Text(
                modifier =
                    Modifier.align(Alignment.Center)
                        .edgeSwipeToDismiss(state)
                        .horizontalScroll(horizontalScrollState),
                text =
                    "This text can be scrolled horizontally - to dismiss, swipe " +
                        "right from the left edge of the screen (called Edge Swiping)",
            )
        }
    }
}

For more information, see the Swipe to dismiss guide.

To set the custom values of background scrim color and content scrim color, provide the composition locals - LocalSwipeToDismissBackgroundScrimColor and LocalSwipeToDismissContentScrimColor.

Parameters
onDismissed: () -> Unit

Executes when the swipe to dismiss has completed.

modifier: Modifier = Modifier

Modifier for this component.

state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState()

State containing information about ongoing swipe or animation.

backgroundKey: Any = SwipeToDismissKeys.Background

key which identifies the content currently composed in the content block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when BasicSwipeToDismissBox is used for the navigation). This allows remembered state to be correctly moved between background and foreground.

contentKey: Any = SwipeToDismissKeys.Content

key which identifies the content currently composed in the content block when isBackground == false. See backgroundKey.

userSwipeEnabled: Boolean = true

Whether the swipe gesture is enabled. (e.g. when there is no background screen, set userSwipeEnabled = false)

content: @Composable BoxScope.(isBackground: Boolean) -> Unit

Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold.

@Composable
fun CurvedLayout(
    modifier: Modifier = Modifier,
    anchor: Float = 270.0f,
    anchorType: AnchorType = AnchorType.Center,
    radialAlignment: CurvedAlignment.Radial? = null,
    angularDirection: CurvedDirection.Angular = CurvedDirection.Angular.Normal,
    contentBuilder: CurvedScope.() -> Unit
): Unit

A layout composable that places its children in an arc, rotating them as needed. This will layout children using a curvedRow, that similar to a Row layout, that it's curved into a segment of an annulus.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    curvedComposable {
        BasicText(
            "Simple",
            Modifier.background(Color.White).padding(2.dp),
            TextStyle(
                color = Color.Black,
                fontSize = 16.sp,
            )
        )
    }
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Gray)) }
    curvedComposable {
        BasicText(
            "CurvedWorld",
            Modifier.background(Color.White).padding(2.dp),
            TextStyle(
                color = Color.Black,
                fontSize = 16.sp,
            )
        )
    }
}
Parameters
modifier: Modifier = Modifier

The modifier to be applied to the CurvedRow.

anchor: Float = 270.0f

The angle at which children are laid out relative to, in degrees. An angle of 0 corresponds to the right (3 o'clock on a watch), 90 degrees is bottom (6 o'clock), and so on. Default is 270 degrees (top of the screen)

anchorType: AnchorType = AnchorType.Center

Specify how the content is drawn with respect to the anchor. Default is to center the content on the anchor.

radialAlignment: CurvedAlignment.Radial? = null

Specifies the radial alignment for children, if not specified, children can choose their own radial Alignment. Alignment specifies where to lay down children that are thiner than the CurvedRow, either closer to the center (INNER), apart from the center (OUTER) or in the middle point (CENTER).

angularDirection: CurvedDirection.Angular = CurvedDirection.Angular.Normal

Specify the direction the children are laid on. See CurvedDirection.Angular. The default is CurvedDirection.Angular.Normal, which is clockwise under a LtR layout and counter clockwise on a RtL layout.

contentBuilder: CurvedScope.() -> Unit

Specifies the content of this layout, currently there are 5 available elements defined in foundations for this DSL: the sub-layouts curvedBox, curvedRow and curvedColumn, basicCurvedText and curvedComposable (used to add normal composables to curved layouts)

HierarchicalFocusCoordinator

@Composable
fun HierarchicalFocusCoordinator(
    requiresFocus: () -> Boolean,
    content: @Composable () -> Unit
): Unit

Coordinates focus for any composables in content and determines which composable will get focus. HierarchicalFocusCoordinators can be nested, and form a tree, with an implicit root. Focus-requiring components (i.e. components using ActiveFocusListener or ActiveFocusRequester) should only be in the leaf HierarchicalFocusCoordinators, and there should be at most one per HierarchicalFocusCoordinator. For HierarchicalFocusCoordinator elements sharing a parent (or at the top level, sharing the implicit root parent), only one should have focus enabled. The selected HierarchicalFocusCoordinator is the one that has focus enabled for itself and all ancestors, it will pass focus to its focus-requiring component if it has one, or call FocusManager#clearFocus() otherwise. If no HierarchicalFocusCoordinator is selected, there will be no change on the focus state.

Example usage:

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.HierarchicalFocusCoordinator
import androidx.wear.compose.foundation.rememberActiveFocusRequester

var selected by remember { mutableStateOf(0) }

Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
    Row(Modifier.fillMaxWidth()) {
        repeat(5) { ix ->
            var focused by remember { mutableStateOf(false) }
            HierarchicalFocusCoordinator(requiresFocus = { selected == ix }) {
                val focusRequester = rememberActiveFocusRequester()
                BasicText(
                    "$ix",
                    style =
                        TextStyle(
                            color = Color.White,
                            fontSize = 20.sp,
                            textAlign = TextAlign.Center
                        ),
                    modifier =
                        Modifier.weight(1f)
                            .clickable { selected = ix }
                            .onFocusChanged { focused = it.isFocused }
                            .focusRequester(focusRequester)
                            .focusable()
                            .then(
                                if (focused) {
                                    Modifier.border(BorderStroke(2.dp, Color.Red))
                                } else {
                                    Modifier
                                }
                            )
                )
            }
        }
    }
}
Parameters
requiresFocus: () -> Boolean

a function should return true when the content subtree of the composition is active and may requires the focus (and false when it's not). For example, a pager can enclose each page's content with a call to HierarchicalFocusCoordinator, marking only the current page as requiring focus.

content: @Composable () -> Unit

The content of this component.

fun ScrollInfoProvider(state: LazyListState): ScrollInfoProvider

Function for creating a ScrollInfoProvider from a LazyListState, for use with LazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

fun ScrollInfoProvider(state: PagerState): ScrollInfoProvider

Function for creating a ScrollInfoProvider from a PagerState, for use with HorizontalPager and VerticalPager

  • used to coordinate when to fade out the PageIndicator and TimeText. The PageIndicator fades out when when scrolling is finished and the screen is in an idle state.

Parameters
state: PagerState

the PagerState to use as the base for creating the ScrollInfoProvider

fun ScrollInfoProvider(state: ScalingLazyListState): ScrollInfoProvider

Function for creating a ScrollInfoProvider from a ScalingLazyListState, for use with ScalingLazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

fun ScrollInfoProvider(state: ScrollState): ScrollInfoProvider

Function for creating a ScrollInfoProvider from a ScrollState, for use with Column - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

Parameters
state: ScrollState

the ScrollState to use as the base for creating the ScrollInfoProvider

fun ScrollInfoProvider(state: TransformingLazyColumnState): ScrollInfoProvider

Function for creating a ScrollInfoProvider from a TransformingLazyColumnState, for use with TransformingLazyColumn - used to coordinate between scrollable content and scaffold content such as TimeText which is scrolled away at the top of the screen and EdgeButton which is scaled.

@Composable
fun SwipeToReveal(
    primaryAction: @Composable RevealScope.() -> Unit,
    modifier: Modifier = Modifier,
    onFullSwipe: () -> Unit = {},
    state: RevealState = rememberRevealState(),
    secondaryAction: (@Composable RevealScope.() -> Unit)? = null,
    undoAction: (@Composable RevealScope.() -> Unit)? = null,
    content: @Composable () -> Unit
): Unit

A composable that can be used to add extra actions to a composable (up to two) which will be revealed when the original composable is swiped to the left. This composable requires a primary swipe/click action, a secondary optional click action can also be provided.

When the composable reaches the state where all the actions are revealed and the swipe continues beyond the positional threshold defined in RevealState, the primary action is automatically triggered.

An optional undo action can also be added. This undo action will be visible to users once the RevealValue becomes RevealValue.RightRevealed.

It is strongly recommended to have icons represent the actions and maybe a text and icon for the undo action.

Example of SwipeToReveal with primary action and undo action

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.wear.compose.foundation.SwipeToReveal
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipDefaults
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.Text

SwipeToReveal(
    modifier =
        Modifier.semantics {
            // Use custom actions to make the primary and secondary actions accessible
            customActions =
                listOf(
                    CustomAccessibilityAction("Delete") {
                        /* Add the primary action click handler */
                        true
                    }
                )
        },
    primaryAction = {
        Box(
            modifier = Modifier.fillMaxSize().clickable { /* Add the primary action */ },
        ) {
            Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete")
        }
    },
    undoAction = {
        Chip(
            modifier = Modifier.fillMaxWidth(),
            onClick = { /* Add undo action here */ },
            colors = ChipDefaults.secondaryChipColors(),
            label = { Text(text = "Undo") }
        )
    }
) {
    Chip(
        modifier = Modifier.fillMaxWidth(),
        onClick = { /* the click action associated with chip */ },
        colors = ChipDefaults.secondaryChipColors(),
        label = { Text(text = "Swipe Me") }
    )
}

Example of SwipeToReveal using RevealScope to delay the appearance of primary action text

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.SwipeToReveal
import androidx.wear.compose.foundation.rememberRevealState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipDefaults
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.Text

val state = rememberRevealState()
SwipeToReveal(
    modifier =
        Modifier.semantics {
            // Use custom actions to make the primary and secondary actions accessible
            customActions =
                listOf(
                    CustomAccessibilityAction("Delete") {
                        /* Add the primary action click handler */
                        true
                    }
                )
        },
    state = state,
    primaryAction = {
        Box(
            modifier = Modifier.fillMaxSize().clickable { /* Add the primary action */ },
        ) {
            Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete")
            if (abs(state.offset) > revealOffset) {
                // Delay the text appearance so that it has enough space to be displayed
                val textAlpha =
                    animateFloatAsState(
                        targetValue = 1f,
                        animationSpec = tween(durationMillis = 250, delayMillis = 250),
                        label = "PrimaryActionTextAlpha"
                    )
                Box(modifier = Modifier.graphicsLayer { alpha = textAlpha.value }) {
                    Spacer(Modifier.size(5.dp))
                    Text("Clear")
                }
            }
        }
    },
    undoAction = {
        Chip(
            modifier = Modifier.fillMaxWidth(),
            onClick = { /* Add undo action here */ },
            colors = ChipDefaults.secondaryChipColors(),
            label = { Text(text = "Undo") }
        )
    }
) {
    Chip(
        modifier = Modifier.fillMaxWidth(),
        onClick = { /* the click action associated with chip */ },
        colors = ChipDefaults.secondaryChipColors(),
        label = { Text(text = "Swipe Me") }
    )
}

Example of SwipeToReveal used with Expandables

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.wear.compose.foundation.RevealValue
import androidx.wear.compose.foundation.SwipeToReveal
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.foundation.rememberRevealState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipDefaults
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.ListHeader
import androidx.wear.compose.material.Text

// Shape of actions should match with the overlay content. For example, Chips
// should use RoundedCornerShape(CornerSize(percent = 50)), Cards should use
// RoundedCornerShape with appropriate radius, based on the theme.
val actionShape = RoundedCornerShape(corner = CornerSize(percent = 50))
val itemCount = 10
val coroutineScope = rememberCoroutineScope()
val expandableStates = List(itemCount) { rememberExpandableState(initiallyExpanded = true) }
ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    item { ListHeader { Text("Scaling Lazy Column") } }
    repeat(itemCount) { current ->
        expandableItem(
            state = expandableStates[current],
        ) { isExpanded ->
            val revealState = rememberRevealState()
            if (isExpanded) {
                SwipeToReveal(
                    modifier =
                        Modifier.semantics {
                            // Use custom actions to make the primary and secondary actions
                            // accessible
                            customActions =
                                listOf(
                                    CustomAccessibilityAction("Delete") {
                                        coroutineScope.launch {
                                            revealState.animateTo(RevealValue.RightRevealed)
                                        }
                                        true
                                    }
                                )
                        },
                    state = revealState,
                    primaryAction = {
                        Box(
                            modifier =
                                Modifier.fillMaxSize()
                                    .background(Color.Red, actionShape)
                                    .clickable {
                                        coroutineScope.launch {
                                            revealState.animateTo(RevealValue.RightRevealed)
                                        }
                                    },
                            contentAlignment = Alignment.Center
                        ) {
                            Icon(
                                imageVector = Icons.Outlined.Delete,
                                contentDescription = "Delete"
                            )
                        }
                    },
                    secondaryAction = {
                        Box(
                            modifier =
                                Modifier.fillMaxSize()
                                    .background(Color.Gray, actionShape)
                                    .clickable { /* trigger the optional action */ },
                            contentAlignment = Alignment.Center
                        ) {
                            Icon(
                                imageVector = Icons.Outlined.MoreVert,
                                contentDescription = "More Options"
                            )
                        }
                    },
                    undoAction = {
                        Chip(
                            modifier = Modifier.fillMaxWidth(),
                            onClick = {
                                coroutineScope.launch {
                                    revealState.animateTo(RevealValue.Covered)
                                }
                            },
                            colors = ChipDefaults.secondaryChipColors(),
                            label = { Text(text = "Undo") }
                        )
                    },
                    onFullSwipe = {
                        coroutineScope.launch {
                            delay(1000)
                            expandableStates[current].expanded = false
                        }
                    }
                ) {
                    Chip(
                        modifier = Modifier.fillMaxWidth(),
                        onClick = { /* the click action associated with chip */ },
                        colors = ChipDefaults.secondaryChipColors(),
                        label = { Text(text = "Swipe Me") }
                    )
                }
            }
        }
    }
}
Parameters
primaryAction: @Composable RevealScope.() -> Unit

The primary action that will be triggered in the event of a completed swipe. We also strongly recommend to trigger the action when it is clicked.

modifier: Modifier = Modifier

Optional Modifier for this component.

onFullSwipe: () -> Unit = {}

An optional lambda which will be triggered when a full swipe from either of the anchors is performed.

state: RevealState = rememberRevealState()

The RevealState of this component. It can be used to customise the anchors and threshold config of the swipeable modifier which is applied.

secondaryAction: (@Composable RevealScope.() -> Unit)? = null

An optional action that can be added to the component. We strongly recommend triggering the action when it is clicked.

undoAction: (@Composable RevealScope.() -> Unit)? = null

The optional undo action that will be applied to the component once the the RevealState.currentValue becomes RevealValue.RightRevealed.

content: @Composable () -> Unit

The content that will be initially displayed over the other actions provided.

fun createAnchors(
    coveredAnchor: Float = 0.0f,
    revealingAnchor: Float = SwipeToRevealDefaults.revealingRatio,
    revealedAnchor: Float = 1.0f,
    swipeDirection: SwipeDirection = SwipeDirection.RightToLeft
): Map<RevealValueFloat>

Creates the required anchors to which the top content can be swiped, to reveal the actions. Each value should be in the range 0..1, where 0 represents right most end and 1 represents the full width of the top content starting from right and ending on left.

Parameters
coveredAnchor: Float = 0.0f

Anchor for the RevealValue.Covered value

revealingAnchor: Float = SwipeToRevealDefaults.revealingRatio

Anchor for the RevealValue.LeftRevealing or RevealValue.RightRevealing value

revealedAnchor: Float = 1.0f

Anchor for the RevealValue.LeftRevealed or RevealValue.RightRevealed value

swipeDirection: SwipeDirection = SwipeDirection.RightToLeft

The direction in which the content can be swiped. It's strongly advised to keep the default SwipeDirection.RightToLeft in order to preserve compatibility with the system wide swipe to dismiss gesture.

rememberActiveFocusRequester

@Composable
fun rememberActiveFocusRequester(): FocusRequester

Creates, remembers and returns a new FocusRequester, that will have .requestFocus called when the enclosing HierarchicalFocusCoordinator becomes active. Note that the location you call this is important, in particular, which HierarchicalFocusCoordinator is enclosing it. Also, this may call requestFocus in the returned FocusRequester, so that focusRequester should be used in a .focusRequester modifier on a Composable that is part of the composition.

rememberExpandableState

@Composable
fun rememberExpandableState(
    initiallyExpanded: Boolean = false,
    expandAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.expandAnimationSpec,
    collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec
): ExpandableState

Create and remember an ExpandableState

Example of an expandable list:

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.expandableButton
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.expandableItems
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.OutlinedCompactChip
import androidx.wear.compose.material.Text

val expandableState = rememberExpandableState()

val sampleItem: @Composable (String) -> Unit = { label ->
    Chip(label = { Text(label) }, onClick = {}, secondaryLabel = { Text("line 2 - Secondary") })
}

val items = List(10) { "Item $it" }
val top = items.take(3)
val rest = items.drop(3)

ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    items(top.size) { sampleItem(top[it]) }
    expandableItems(expandableState, rest.size) { sampleItem(rest[it]) }
    expandableButton(expandableState) {
        OutlinedCompactChip(
            label = {
                Text("Show More")
                Spacer(Modifier.size(6.dp))
                Icon(painterResource(R.drawable.ic_expand_more_24), "Expand")
            },
            onClick = { expandableState.expanded = true }
        )
    }
}

Example of an expandable text:

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.expandableButton
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.OutlinedCompactChip
import androidx.wear.compose.material.Text

val expandableState = rememberExpandableState()

ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    expandableItem(expandableState) { expanded ->
        Text(
            "Account Alert: you have made a large purchase.\n" +
                "We have noticed that a large purchase was charged to " +
                "your credit card account. " +
                "Please contact us if you did not perform this purchase. " +
                "Our Customer Service team is available 24 hours a day, " +
                "7 days a week to answer your account or product support question.",
            maxLines = if (expanded) 20 else 3,
            modifier = Modifier.padding(horizontal = 10.dp)
        )
    }

    expandableButton(expandableState) {
        OutlinedCompactChip(
            label = {
                Text("Show More")
                Spacer(Modifier.size(6.dp))
                Icon(painterResource(R.drawable.ic_expand_more_24), "Expand")
            },
            onClick = { expandableState.expanded = true }
        )
    }
}
Parameters
initiallyExpanded: Boolean = false

The initial value of the state.

expandAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.expandAnimationSpec

The AnimationSpec to use when showing the extra information.

collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec

The AnimationSpec to use when hiding the extra information.

rememberExpandableStateMapping

@Composable
@ExperimentalWearFoundationApi
fun <T : Any?> rememberExpandableStateMapping(
    initiallyExpanded: (key) -> Boolean = { false },
    expandAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.expandAnimationSpec,
    collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec
): ExpandableStateMapping<T>

Create and remember a mapping from keys to ExpandableStates ExpandableStates can be requested by key, and we will created with the parameters given here when a mapping didn't exist before. This is mainly useful when you want to have a variable number of expandables, that can change at runtime (for example, elements on a ScalingLazyColumn)

Parameters
initiallyExpanded: (key) -> Boolean = { false }

A function to compute the initial state given the key.

expandAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.expandAnimationSpec

The AnimationSpec to use when showing the extra information.

collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec

The AnimationSpec to use when hiding the extra information.

@Composable
fun rememberRevealState(
    initialValue: RevealValue = RevealValue.Covered,
    animationSpec: AnimationSpec<Float> = SwipeToRevealDefaults.animationSpec,
    confirmValueChange: (RevealValue) -> Boolean = { true },
    positionalThreshold: Density.(totalDistance: Float) -> Float = SwipeToRevealDefaults.positionalThreshold,
    anchors: Map<RevealValueFloat> = createAnchors()
): RevealState

Create and remember a RevealState.

Parameters
initialValue: RevealValue = RevealValue.Covered

The initial value of the RevealValue.

animationSpec: AnimationSpec<Float> = SwipeToRevealDefaults.animationSpec

The animation which will be applied on the top content.

confirmValueChange: (RevealValue) -> Boolean = { true }

Optional callback invoked to confirm or veto a pending state change.

positionalThreshold: Density.(totalDistance: Float) -> Float = SwipeToRevealDefaults.positionalThreshold

The positional threshold to be used when calculating the target state while the reveal is in progress and when settling after the revealing ends. This is the distance from the start of a transition. It will be, depending on the direction of the interaction, added or subtracted from/to the origin offset. It should always be a positive value.

anchors: Map<RevealValueFloat> = createAnchors()

A map of RevealValue to the fraction where the content can be revealed to reach that value. Each anchor should be between 0..1 which will be adjusted based on total width.

rememberSwipeToDismissBoxState

@Composable
fun rememberSwipeToDismissBoxState(
    animationSpec: AnimationSpec<Float> = SWIPE_TO_DISMISS_BOX_ANIMATION_SPEC,
    confirmStateChange: (SwipeToDismissValue) -> Boolean = { true }
): SwipeToDismissBoxState

Create a SwipeToDismissBoxState and remember it.

Parameters
animationSpec: AnimationSpec<Float> = SWIPE_TO_DISMISS_BOX_ANIMATION_SPEC

The default animation used to animate to a new state.

confirmStateChange: (SwipeToDismissValue) -> Boolean = { true }

callback to confirm or veto a pending state change.

Extension functions

angularGradientBackground

fun CurvedModifier.angularGradientBackground(
    vararg colorStops: Pair<FloatColor>,
    cap: StrokeCap = StrokeCap.Butt
): CurvedModifier

Specifies a sweep gradient background for a curved element.

Example usage:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.angularGradientBackground
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.radialGradientBackground

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "Radial",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.radialGradientBackground(0f to Color.White, 1f to Color.Black)
                .padding(5.dp)
    )
    basicCurvedText(
        "Angular",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.angularGradientBackground(0f to Color.White, 1f to Color.Black)
                .padding(5.dp)
    )
}
Parameters
vararg colorStops: Pair<FloatColor>

Colors and their offset in the gradient area. Note that the offsets should be in ascending order. 0 means where the curved element starts laying out, 1 means the end

cap: StrokeCap = StrokeCap.Butt

How to start and end the background.

angularGradientBackground

fun CurvedModifier.angularGradientBackground(
    colors: List<Color>,
    cap: StrokeCap = StrokeCap.Butt
): CurvedModifier

Specifies a sweep gradient background for a curved element.

Parameters
colors: List<Color>

Colors in the gradient area. Gradient goes in the clockwise direction.

cap: StrokeCap = StrokeCap.Butt

How to start and end the background.

fun CurvedModifier.angularSize(sweepDegrees: Float): CurvedModifier

Specify the sweep (angular size) for the content.

Parameters
sweepDegrees: Float

Indicates the sweep (angular size) of the content.

fun CurvedModifier.angularSizeDp(angularWidth: Dp): CurvedModifier

Specify the sweep (arc length) for the content in Dp. The arc length will be measured at the center of the item, except for basicCurvedText, where it will be measured at the text baseline.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.angularSize
import androidx.wear.compose.foundation.angularSizeDp
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.radialSize
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "45 deg",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.background(Color.White).size(sweepDegrees = 45f, thickness = 40.dp),
    )
    basicCurvedText(
        "40 dp",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.background(Color.Yellow).radialSize(40.dp).angularSizeDp(40.dp),
    )
}
Parameters
angularWidth: Dp

Indicates the arc length of the content in Dp.

fun CurvedModifier.background(color: Color, cap: StrokeCap = StrokeCap.Butt): CurvedModifier

Specified a solid background for a curved element.

Parameters
color: Color

The color to use to paint the background.

cap: StrokeCap = StrokeCap.Butt

How to start and end the background.

fun CurvedScope.basicCurvedText(
    text: String,
    modifier: CurvedModifier = CurvedModifier,
    angularDirection: CurvedDirection.Angular? = null,
    overflow: TextOverflow = TextOverflow.Clip,
    style: @Composable () -> CurvedTextStyle = { CurvedTextStyle() }
): Unit

basicCurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen). basicCurvedText can be only created within a CurvedLayout since it's not a composable.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "Curved Text",
        CurvedModifier.padding(10.dp),
        style = {
            CurvedTextStyle(fontSize = 16.sp, color = Color.Black, background = Color.White)
        }
    )
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Gray)) }
    curvedComposable {
        BasicText(
            "Normal Text",
            Modifier.padding(5.dp),
            TextStyle(fontSize = 16.sp, color = Color.Black, background = Color.White)
        )
    }
}
Parameters
text: String

The text to display

modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved text.

angularDirection: CurvedDirection.Angular? = null

Specify if the text is laid out clockwise or anti-clockwise, and if those needs to be reversed in a Rtl layout. If not specified, it will be inherited from the enclosing curvedRow or CurvedLayout See CurvedDirection.Angular.

overflow: TextOverflow = TextOverflow.Clip

How visual overflow should be handled.

style: @Composable () -> CurvedTextStyle = { CurvedTextStyle() }

A @Composable factory to provide the style to use. This composable SHOULDN'T generate any compose nodes.

fun CurvedScope.basicCurvedText(
    text: String,
    style: CurvedTextStyle,
    modifier: CurvedModifier = CurvedModifier,
    angularDirection: CurvedDirection.Angular? = null,
    overflow: TextOverflow = TextOverflow.Clip
): Unit

basicCurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen). basicCurvedText can be only created within a CurvedLayout since it's not a composable.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "Curved Text",
        CurvedModifier.padding(10.dp),
        style = {
            CurvedTextStyle(fontSize = 16.sp, color = Color.Black, background = Color.White)
        }
    )
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Gray)) }
    curvedComposable {
        BasicText(
            "Normal Text",
            Modifier.padding(5.dp),
            TextStyle(fontSize = 16.sp, color = Color.Black, background = Color.White)
        )
    }
}
Parameters
text: String

The text to display

style: CurvedTextStyle

A style to use.

modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved text.

angularDirection: CurvedDirection.Angular? = null

Specify if the text is laid out clockwise or anti-clockwise, and if those needs to be reversed in a Rtl layout. If not specified, it will be inherited from the enclosing curvedRow or CurvedLayout See CurvedDirection.Angular.

overflow: TextOverflow = TextOverflow.Clip

How visual overflow should be handled.

fun CurvedScope.curvedBox(
    modifier: CurvedModifier = CurvedModifier,
    radialAlignment: CurvedAlignment.Radial? = null,
    angularAlignment: CurvedAlignment.Angular? = null,
    contentBuilder: CurvedScope.() -> Unit
): Unit

A layout composable that places its children on top of each other and on an arc. This is similar to a Box layout, but curved into a segment of an annulus.

The thickness of the layout (the difference between the outer and inner radius) will be the same as the thickest child, and the angle taken will be the biggest angle of the children.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.CurvedAlignment
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedBox
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    curvedBox(
        modifier = CurvedModifier.background(Color.Red),
        radialAlignment = CurvedAlignment.Radial.Inner,
        angularAlignment = CurvedAlignment.Angular.End
    ) {
        curvedComposable {
            Box(modifier = Modifier.width(40.dp).height(80.dp).background(Color.Green))
        }
        curvedComposable {
            Box(modifier = Modifier.size(30.dp).clip(CircleShape).background(Color.White))
        }
    }
}
Parameters
modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved row.

radialAlignment: CurvedAlignment.Radial? = null

Radial alignment specifies where to lay down children that are thinner than the CurvedBox, either closer to the center CurvedAlignment.Radial.Inner, apart from the center CurvedAlignment.Radial.Outer or in the middle point CurvedAlignment.Radial.Center. If unspecified, they can choose for themselves.

angularAlignment: CurvedAlignment.Angular? = null

Angular alignment specifies where to lay down children that are thinner than the CurvedBox, either at the CurvedAlignment.Angular.Start of the layout, at the CurvedAlignment.Angular.End, or CurvedAlignment.Angular.Center. If unspecified or null, they can choose for themselves.

contentBuilder: CurvedScope.() -> Unit

Specifies the content of this layout, currently there are 5 available elements defined in foundation for this DSL: the sub-layouts curvedBox, curvedRow and curvedColumn, basicCurvedText and curvedComposable (used to add normal composables to curved layouts)

fun CurvedScope.curvedColumn(
    modifier: CurvedModifier = CurvedModifier,
    radialDirection: CurvedDirection.Radial? = null,
    angularAlignment: CurvedAlignment.Angular? = null,
    contentBuilder: CurvedScope.() -> Unit
): Unit

A curved layout composable that places its children stacked as part of an arc (the first child will be the outermost). This is similar to a Column layout, but curved into a segment of an annulus.

The thickness of the layout (the difference between the outer and inner radius) will be the sum of the thickness of its children, and the angle taken will be the biggest angle of the children.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedAlignment
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedColumn
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Red)) }
    curvedColumn(angularAlignment = CurvedAlignment.Angular.End) {
        repeat(3) {
            curvedRow {
                curvedComposable {
                    BasicText(
                        "Row #$it",
                        Modifier.background(Color.White).padding(2.dp),
                        TextStyle(
                            color = Color.Black,
                            fontSize = 14.sp,
                        )
                    )
                }
                curvedComposable {
                    Box(modifier = Modifier.size(10.dp).background(Color.Green))
                }
                curvedComposable {
                    BasicText(
                        "More",
                        Modifier.background(Color.Yellow).padding(2.dp),
                        TextStyle(
                            color = Color.Black,
                            fontSize = 14.sp,
                        )
                    )
                }
            }
        }
    }
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Red)) }
}
Parameters
modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved column.

radialDirection: CurvedDirection.Radial? = null

Order to lay out components, outside in or inside out. The default is to inherit from the containing curvedColumn or CurvedLayout

angularAlignment: CurvedAlignment.Angular? = null

Angular alignment specifies where to lay down children that are thinner than the curved column, either at the CurvedAlignment.Angular.Start of the layout, at the CurvedAlignment.Angular.End, or CurvedAlignment.Angular.Center. If unspecified or null, they can choose for themselves.

contentBuilder: CurvedScope.() -> Unit

Scope used to provide the content for this column.

fun CurvedScope.curvedComposable(
    modifier: CurvedModifier = CurvedModifier,
    radialAlignment: CurvedAlignment.Radial = CurvedAlignment.Radial.Center,
    rotationLocked: Boolean = false,
    content: @Composable BoxScope.() -> Unit
): Unit

Component that allows normal composables to be part of a CurvedLayout.

Parameters
modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved composable.

radialAlignment: CurvedAlignment.Radial = CurvedAlignment.Radial.Center

How to align this component if it's thinner than the container.

rotationLocked: Boolean = false

by default (when this is false), the component will be rotated as it moves around the circle, so its base always faces the center. If set to true, it won't be rotated and only moved into position, for example, an upwards pointing arrow will remain pointing upwards wherever it appears on the circle. Note that this is not taken into account when computing the size this will take in the layout, so it's best suited for square/circular things and may require manual sizing when used in other contexts.

content: @Composable BoxScope.() -> Unit

The composable(s) that will be wrapped and laid out as part of the parent container. This has a BoxScope, since it's wrapped inside a Box.

fun CurvedScope.curvedRow(
    modifier: CurvedModifier = CurvedModifier,
    radialAlignment: CurvedAlignment.Radial? = null,
    angularDirection: CurvedDirection.Angular? = null,
    contentBuilder: CurvedScope.() -> Unit
): Unit

A layout composable that places its children in an arc, rotating them as needed. This is similar to a Row layout, but curved into a segment of an annulus.

The thickness of the layout (the difference between the outer and inner radius) will be the same as the thickest child, and the total angle taken is the sum of the children's angles.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedAlignment
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedColumn
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Red)) }
    curvedColumn(angularAlignment = CurvedAlignment.Angular.End) {
        repeat(3) {
            curvedRow {
                curvedComposable {
                    BasicText(
                        "Row #$it",
                        Modifier.background(Color.White).padding(2.dp),
                        TextStyle(
                            color = Color.Black,
                            fontSize = 14.sp,
                        )
                    )
                }
                curvedComposable {
                    Box(modifier = Modifier.size(10.dp).background(Color.Green))
                }
                curvedComposable {
                    BasicText(
                        "More",
                        Modifier.background(Color.Yellow).padding(2.dp),
                        TextStyle(
                            color = Color.Black,
                            fontSize = 14.sp,
                        )
                    )
                }
            }
        }
    }
    curvedComposable { Box(modifier = Modifier.size(20.dp).background(Color.Red)) }
}
Parameters
modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved row.

radialAlignment: CurvedAlignment.Radial? = null

Radial alignment specifies where to lay down children that are thinner than the CurvedRow, either closer to the center CurvedAlignment.Radial.Inner, apart from the center CurvedAlignment.Radial.Outer or in the middle point CurvedAlignment.Radial.Center. If unspecified, they can choose for themselves.

angularDirection: CurvedDirection.Angular? = null

Specify if the children are laid out clockwise or anti-clockwise, and if those needs to be reversed in a Rtl layout. If not specified, it will be inherited from the enclosing curvedRow or CurvedLayout See CurvedDirection.Angular.

contentBuilder: CurvedScope.() -> Unit

Scope used to provide the content for this row.

fun Modifier.edgeSwipeToDismiss(
    swipeToDismissBoxState: SwipeToDismissBoxState,
    edgeWidth: Dp = SwipeToDismissBoxDefaults.EdgeWidth
): Modifier

Limits swipe to dismiss to be active from the edge of the viewport only. Used when the center of the screen needs to be able to handle horizontal paging, such as 2-d scrolling a Map or swiping horizontally between pages. Swipe to the right is intercepted on the left part of the viewport with width specified by edgeWidth, with other touch events ignored - vertical scroll, click, long click, etc.

Currently Edge swipe, like swipe to dismiss, is only supported on the left part of the viewport regardless of layout direction as content is swiped away from left to right.

Requires that the element to which this modifier is applied exists within a BasicSwipeToDismissBox which is using the same SwipeToDismissBoxState instance.

Example of a modifier usage with SwipeToDismiss

import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.BasicSwipeToDismissBox
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text

val state = rememberSwipeToDismissBoxState()

// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
BasicSwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    val horizontalScrollState = rememberScrollState(0)
    if (isBackground) {
        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
        Box(modifier = Modifier.fillMaxSize()) {
            Text(
                modifier =
                    Modifier.align(Alignment.Center)
                        .edgeSwipeToDismiss(state)
                        .horizontalScroll(horizontalScrollState),
                text =
                    "This text can be scrolled horizontally - to dismiss, swipe " +
                        "right from the left edge of the screen (called Edge Swiping)",
            )
        }
    }
}
Parameters
swipeToDismissBoxState: SwipeToDismissBoxState

State of BasicSwipeToDismissBox. Used to trigger swipe gestures on SwipeToDismissBox.

edgeWidth: Dp = SwipeToDismissBoxDefaults.EdgeWidth

Width of the edge zone in which the swipe will be recognised.

expandableButton

fun ScalingLazyListScope.expandableButton(
    state: ExpandableState,
    key: Any? = null,
    content: @Composable () -> Unit
): Unit

Adds a single item, for the button that controls expandable item(s). The button will be animated out when the corresponding expandables are expanded.

Example of an expandable text:

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.expandableButton
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.OutlinedCompactChip
import androidx.wear.compose.material.Text

val expandableState = rememberExpandableState()

ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    expandableItem(expandableState) { expanded ->
        Text(
            "Account Alert: you have made a large purchase.\n" +
                "We have noticed that a large purchase was charged to " +
                "your credit card account. " +
                "Please contact us if you did not perform this purchase. " +
                "Our Customer Service team is available 24 hours a day, " +
                "7 days a week to answer your account or product support question.",
            maxLines = if (expanded) 20 else 3,
            modifier = Modifier.padding(horizontal = 10.dp)
        )
    }

    expandableButton(expandableState) {
        OutlinedCompactChip(
            label = {
                Text("Show More")
                Spacer(Modifier.size(6.dp))
                Icon(painterResource(R.drawable.ic_expand_more_24), "Expand")
            },
            onClick = { expandableState.expanded = true }
        )
    }
}
Parameters
state: ExpandableState

The ExpandableState to connect this button to.

key: Any? = null

A stable and unique key representing the item. Using the same key for multiple items in the list is not allowed. Type of the key should be saveable via Bundle on Android. If null is passed the position in the list will represent the key. When you specify the key the scroll position will be maintained based on the key, which means if you add/remove items before the current visible item the item with the given key will be kept as the first visible one.

content: @Composable () -> Unit

the content displayed, this should usually be a CompactChip or OutlineCompactChip.

expandableItem

fun ScalingLazyListScope.expandableItem(
    state: ExpandableState,
    key: Any? = null,
    content: @Composable (expanded: Boolean) -> Unit
): Unit

Adds a single item, that will be expanded/collapsed according to the ExpandableState.

Example of an expandable text:

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.expandableButton
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.OutlinedCompactChip
import androidx.wear.compose.material.Text

val expandableState = rememberExpandableState()

ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    expandableItem(expandableState) { expanded ->
        Text(
            "Account Alert: you have made a large purchase.\n" +
                "We have noticed that a large purchase was charged to " +
                "your credit card account. " +
                "Please contact us if you did not perform this purchase. " +
                "Our Customer Service team is available 24 hours a day, " +
                "7 days a week to answer your account or product support question.",
            maxLines = if (expanded) 20 else 3,
            modifier = Modifier.padding(horizontal = 10.dp)
        )
    }

    expandableButton(expandableState) {
        OutlinedCompactChip(
            label = {
                Text("Show More")
                Spacer(Modifier.size(6.dp))
                Icon(painterResource(R.drawable.ic_expand_more_24), "Expand")
            },
            onClick = { expandableState.expanded = true }
        )
    }
}

The item should support two levels of information display (for example, a text showing a few lines in the collapsed state, and more in the expanded state)

Parameters
state: ExpandableState

The ExpandableState connected to this item.

key: Any? = null

A stable and unique key representing the item. Using the same key for multiple items in the list is not allowed. Type of the key should be saveable via Bundle on Android. If null is passed the position in the list will represent the key. When you specify the key the scroll position will be maintained based on the key, which means if you add/remove items before the current visible item the item with the given key will be kept as the first visible one.

content: @Composable (expanded: Boolean) -> Unit

the content displayed by the item, according to its expanded/collapsed state.

expandableItems

fun ScalingLazyListScope.expandableItems(
    state: ExpandableState,
    count: Int,
    key: ((index: Int) -> Any)? = null,
    itemContent: @Composable BoxScope.(index: Int) -> Unit
): Unit

Adds a series of items, that will be expanded/collapsed according to the ExpandableState

Example of an expandable list:

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.expandableButton
import androidx.wear.compose.foundation.expandableItem
import androidx.wear.compose.foundation.expandableItems
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.OutlinedCompactChip
import androidx.wear.compose.material.Text

val expandableState = rememberExpandableState()

val sampleItem: @Composable (String) -> Unit = { label ->
    Chip(label = { Text(label) }, onClick = {}, secondaryLabel = { Text("line 2 - Secondary") })
}

val items = List(10) { "Item $it" }
val top = items.take(3)
val rest = items.drop(3)

ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
    items(top.size) { sampleItem(top[it]) }
    expandableItems(expandableState, rest.size) { sampleItem(rest[it]) }
    expandableButton(expandableState) {
        OutlinedCompactChip(
            label = {
                Text("Show More")
                Spacer(Modifier.size(6.dp))
                Icon(painterResource(R.drawable.ic_expand_more_24), "Expand")
            },
            onClick = { expandableState.expanded = true }
        )
    }
}
Parameters
state: ExpandableState

The ExpandableState connected to these items.

count: Int

The number of items

key: ((index: Int) -> Any)? = null

a factory of stable and unique keys representing the item. Using the same key for multiple items in the list is not allowed. Type of the key should be saveable via Bundle on Android. If null is passed the position in the list will represent the key. When you specify the key the scroll position will be maintained based on the key, which means if you add/remove items before the current visible item the item with the given key will be kept as the first visible one.

itemContent: @Composable BoxScope.(index: Int) -> Unit

the content displayed by a single item

fun CurvedModifier.padding(all: Dp = 0.dp): CurvedModifier

Apply all dp space around the component.

Parameters
all: Dp = 0.dp

The space added to all edges.

fun CurvedModifier.padding(paddingValues: ArcPaddingValues): CurvedModifier

Apply additional space along the edges of the content.

Parameters
paddingValues: ArcPaddingValues

The ArcPaddingValues to use. See that class and factory methods to see how paddings can be specified.

fun CurvedModifier.padding(radial: Dp = 0.dp, angular: Dp = 0.dp): CurvedModifier

Apply angular dp space before and after the component, and radial dp space to the outer and inner edges.

Parameters
radial: Dp = 0.dp

The space added to the outer and inner edges of the content, in dp.

angular: Dp = 0.dp

The space added before and after the content, in dp.

fun CurvedModifier.padding(outer: Dp, inner: Dp, before: Dp, after: Dp): CurvedModifier

Apply additional space along the edges of the content. Dimmensions are in dp. For before and after they will be considered as if they are at the midpoint of the content (for conversion between dimension and angle).

Parameters
outer: Dp

The space to add to the outer edge of the content (away from the center of the containing CurvedLayout)

inner: Dp

The space to add to the inner edge of the content (towards the center of the containing CurvedLayout)

before: Dp

The space added before the component, if it was draw clockwise. This is the edge of the component with the "smallest" angle.

after: Dp

The space added after the component, if it was draw clockwise. This is the edge of the component with the "biggest" angle.

parentDataModifier

fun CurvedModifier.parentDataModifier(modifyParentData: (Any?) -> Any?): CurvedModifier

A CurvedModifier that provides data to the parent layout. The parent data is commonly used to inform the parent how the child Layout should be measured and positioned.

Parameters
modifyParentData: (Any?) -> Any?

provides a parentData, given the parentData provided through the modifier's chain.

radialGradientBackground

fun CurvedModifier.radialGradientBackground(
    vararg colorStops: Pair<FloatColor>,
    cap: StrokeCap = StrokeCap.Butt
): CurvedModifier

Specifies a radial gradient background for a curved element.

Example usage:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.angularGradientBackground
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.padding
import androidx.wear.compose.foundation.radialGradientBackground

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "Radial",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.radialGradientBackground(0f to Color.White, 1f to Color.Black)
                .padding(5.dp)
    )
    basicCurvedText(
        "Angular",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.angularGradientBackground(0f to Color.White, 1f to Color.Black)
                .padding(5.dp)
    )
}
Parameters
vararg colorStops: Pair<FloatColor>

Colors and their offset in the gradient area. Note that the offsets should be in ascending order. 0 means the outer curve and 1 means the inner curve of the curved element.

cap: StrokeCap = StrokeCap.Butt

How to start and end the background.

radialGradientBackground

fun CurvedModifier.radialGradientBackground(
    colors: List<Color>,
    cap: StrokeCap = StrokeCap.Butt
): CurvedModifier

Specifies a radial gradient background for a curved element.

Parameters
colors: List<Color>

Colors in the gradient area. Gradient goes from the outer curve to the inner curve of the curved element.

cap: StrokeCap = StrokeCap.Butt

How to start and end the background.

fun CurvedModifier.radialSize(thickness: Dp): CurvedModifier

Specify the radialSize (thickness) for the content.

Parameters
thickness: Dp

Indicates the thickness of the content.

fun CurvedModifier.size(
    sweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float,
    thickness: Dp
): CurvedModifier

Specify the dimensions (sweep and thickness) for the content.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.CurvedTextStyle
import androidx.wear.compose.foundation.angularSize
import androidx.wear.compose.foundation.angularSizeDp
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.radialSize
import androidx.wear.compose.foundation.size

CurvedLayout(modifier = Modifier.fillMaxSize()) {
    basicCurvedText(
        "45 deg",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.background(Color.White).size(sweepDegrees = 45f, thickness = 40.dp),
    )
    basicCurvedText(
        "40 dp",
        style = { CurvedTextStyle(fontSize = 16.sp, color = Color.Black) },
        modifier =
            CurvedModifier.background(Color.Yellow).radialSize(40.dp).angularSizeDp(40.dp),
    )
}
Parameters
sweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float

Indicates the sweep (angular size) of the content.

thickness: Dp

Indicates the thickness (radial size) of the content.

fun CurvedModifier.sizeIn(
    minSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float = 0.0f,
    maxSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float = 360.0f,
    minThickness: Dp = 0.dp,
    maxThickness: Dp = Dp.Infinity
): CurvedModifier

Specify the dimensions of the content to be restricted between the given bounds.

Parameters
minSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float = 0.0f

the minimum angle (in degrees) for the content.

maxSweepDegrees: @FloatRange(from = 0.0, to = 360.0) Float = 360.0f

the maximum angle (in degrees) for the content.

minThickness: Dp = 0.dp

the minimum thickness (radial size) for the content.

maxThickness: Dp = Dp.Infinity

the maximum thickness (radial size) for the content.

fun CurvedModifier.weight(
    weight: @FloatRange(from = 0.0, fromInclusive = false) Float
): CurvedModifier

Size the element's proportional to its weight relative to other weighted sibling elements in the container (this will be the height in a curvedColumn and the width in a curvedRow). The parent will divide the space remaining after measuring unweighted child elements and distribute it according to this weight.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.sp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.angularSize
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.basicCurvedText
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.foundation.weight

CurvedLayout(modifier = Modifier.fillMaxSize().background(Color.White)) {
    // Evenly spread A, B & C in a 90 degree angle.
    curvedRow(modifier = CurvedModifier.angularSize(90f)) {
        basicCurvedText("A")
        curvedRow(
            modifier = CurvedModifier.weight(1f),
        ) {}
        basicCurvedText("B")
        curvedRow(
            modifier = CurvedModifier.weight(1f),
        ) {}
        basicCurvedText("C")
    }
}
Parameters
weight: @FloatRange(from = 0.0, fromInclusive = false) Float

The proportional size to give to this element, as related to the total of all weighted siblings. Must be positive.

Top-level properties

LocalReduceMotion

val LocalReduceMotionProvidableCompositionLocal<ReduceMotion>

CompositionLocal for global reduce-motion setting, which turns off animations and screen movements. To use, call LocalReduceMotion.current.enabled(), which returns a Boolean.

LocalSwipeToDismissBackgroundScrimColor

val LocalSwipeToDismissBackgroundScrimColorProvidableCompositionLocal<Color>

CompositionLocal containing the background scrim color of BasicSwipeToDismissBox.

Defaults to Color.Black if not explicitly set.

LocalSwipeToDismissContentScrimColor

val LocalSwipeToDismissContentScrimColorProvidableCompositionLocal<Color>

CompositionLocal containing the content scrim color of BasicSwipeToDismissBox.

Defaults to Color.Black if not explicitly set.