androidx.wear.compose.foundation
Interfaces
ArcPaddingValues |
Apply additional space along each edge of the content in |
CurvedAlignment |
|
CurvedDirection |
|
CurvedModifier |
An ordered, immutable, collection of modifier elements that work with curved components, in a polar coordinate space. |
GestureInclusion |
|
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 |
CurvedDirection.Radial |
The direction in which components are lay down on a |
CurvedScope |
Layout scope used for curved containers. |
CurvedSemanticsScope |
CurvedSemanticsScope is the scope provided by semantics lambda blocks, letting you set semantic properties. |
CurvedTextStyle |
Styling configuration for a curved text. |
CurvedTextStyle.WarpOffset |
Used to specify if we want to warp the text, and if so, the offset for warping. |
ExpandableState |
State of the Expandable composables. |
ExpandableStateMapping |
A class that maps from keys of the given type to |
RevealActionType |
This class is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
RevealDirection |
This class is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
RevealState |
This class is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
RevealValue |
This class is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
SwipeToDismissBoxState |
State for |
Objects
CurvedModifier.Companion |
The companion object |
ExpandableItemsDefaults |
Contains the default values used by Expandable components. |
SwipeToDismissBoxDefaults |
Contains defaults for |
SwipeToRevealDefaults |
This object is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
Annotations
Enums
SwipeToDismissKeys |
Keys used to persistent state in |
SwipeToDismissValue |
States used as targets for the anchor points for swipe-to-dismiss. |
Top-level functions summary
Unit |
@ComposableThis function is deprecated. Replaced by Modifier.requestFocusOnHierarchyActive(), or the new LocalScreenIsActive, use that instead |
ArcPaddingValues |
ArcPaddingValues(all: Dp)Apply |
ArcPaddingValues |
ArcPaddingValues(radial: Dp, angular: Dp)Apply |
ArcPaddingValues |
ArcPaddingValues(outer: Dp, inner: Dp, before: Dp, after: Dp)Apply additional space along each edge of the content in |
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@ComposableA layout composable that places its children in an arc, rotating them as needed. |
Unit |
@ComposableThis function is deprecated. Replaced by Modifier.hierarchicalFocusGroup(), use that instead |
ScrollInfoProvider |
ScrollInfoProvider(state: LazyListState)Function for creating a |
ScrollInfoProvider |
ScrollInfoProvider(state: PagerState)Function for creating a |
ScrollInfoProvider |
Function for creating a |
ScrollInfoProvider |
ScrollInfoProvider(state: ScrollState)Function for creating a |
ScrollInfoProvider |
Function for creating a |
Unit |
@ExperimentalWearFoundationApiThis function is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
Map<RevealValue, Float> |
@ExperimentalWearFoundationApiThis function is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
FocusRequester |
This function is deprecated. Replaced by Modifier.requestFocusOnHierarchyActive(), use that instead |
ExpandableState |
@ComposableCreate and |
ExpandableStateMapping<T> |
@ComposableCreate and |
RevealState |
@ExperimentalWearFoundationApiThis function is deprecated. The SwipeToReveal component from the latest material library should be used instead. |
SwipeToDismissBoxState |
@ComposableCreate a |
Extension functions summary
CurvedModifier |
CurvedModifier.angularGradientBackground(Specifies a sweep gradient background for a curved element. |
CurvedModifier |
CurvedModifier.angularGradientBackground(Specifies a sweep gradient background for a curved element. |
CurvedModifier |
CurvedModifier.angularSize(sweepDegrees: Float)Specify the sweep (angular size) for the content. |
CurvedModifier |
CurvedModifier.angularSizeDp(angularWidth: Dp)Specify the sweep (arc length) for the content in Dp. |
CurvedModifier |
CurvedModifier.background(color: Color, cap: StrokeCap)Specified a solid background for a curved element. |
Unit |
CurvedScope.basicCurvedText(
|
Unit |
CurvedScope.basicCurvedText(
|
CurvedModifier |
CurvedModifier.clearAndSetSemantics(properties: CurvedSemanticsScope.() -> Unit)Allow specifying semantic properties on a curved component, and clearing the existing properties. |
Unit |
CurvedScope.curvedBox(A layout composable that places its children on top of each other and on an arc. |
Unit |
CurvedScope.curvedColumn(A curved layout composable that places its children stacked as part of an arc (the first child will be the outermost). |
Unit |
CurvedScope.curvedComposable(Component that allows normal composables to be part of a |
Unit |
CurvedScope.curvedRow(A layout composable that places its children in an arc, rotating them as needed. |
Modifier |
Modifier.edgeSwipeToDismiss(Handles swipe to dismiss from the edge of the viewport. |
Unit |
ScalingLazyListScope.expandableButton(Adds a single item, for the button that controls expandable item(s). |
Unit |
ScalingLazyListScope.expandableItem(Adds a single item, that will be expanded/collapsed according to the |
Unit |
ScalingLazyListScope.expandableItems(Adds a series of items, that will be expanded/collapsed according to the |
Modifier |
Modifier.hierarchicalFocusGroup(active: Boolean)
|
CurvedModifier |
CurvedModifier.padding(all: Dp)Apply |
CurvedModifier |
CurvedModifier.padding(paddingValues: ArcPaddingValues)Apply additional space along the edges of the content. |
CurvedModifier |
CurvedModifier.padding(radial: Dp, angular: Dp)Apply |
CurvedModifier |
Apply additional space along the edges of the content. |
CurvedModifier |
CurvedModifier.parentDataModifier(modifyParentData: (Any?) -> Any?)A |
CurvedModifier |
CurvedModifier.radialGradientBackground(Specifies a radial gradient background for a curved element. |
CurvedModifier |
CurvedModifier.radialGradientBackground(Specifies a radial gradient background for a curved element. |
CurvedModifier |
CurvedModifier.radialSize(thickness: Dp)Specify the radialSize (thickness) for the content. |
Modifier |
This Modifier is used in conjunction with |
CurvedModifier |
CurvedModifier.semantics(properties: CurvedSemanticsScope.() -> Unit)Allow specifying semantic properties on a curved component. |
CurvedModifier |
CurvedModifier.size(Specify the dimensions (sweep and thickness) for the content. |
CurvedModifier |
CurvedModifier.sizeIn(Specify the dimensions of the content to be restricted between the given bounds. |
CurvedModifier |
CurvedModifier.weight(Size the element's proportional to its |
Top-level properties summary
ProvidableCompositionLocal<Boolean> |
|
ProvidableCompositionLocal<Boolean> |
|
ProvidableCompositionLocal<Color> |
|
ProvidableCompositionLocal<Color> |
|
Top-level functions
ActiveFocusListener
@Composable
funActiveFocusListener(onFocusChanged: CoroutineScope.(Boolean) -> Unit): Unit
ArcPaddingValues
fun ArcPaddingValues(all: Dp): ArcPaddingValues
Apply all dp of additional space along each edge of the content.
ArcPaddingValues
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.
ArcPaddingValues
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 |
inner: Dp = 0.dp |
Padding in the inwards direction towards the center of the |
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 |
|
modifier: Modifier = Modifier |
|
backgroundKey: Any = SwipeToDismissKeys.Background |
|
contentKey: Any = SwipeToDismissKeys.Content |
|
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 |
|
state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState() |
|
backgroundKey: Any = SwipeToDismissKeys.Background |
|
contentKey: Any = SwipeToDismissKeys.Content |
|
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. |
CurvedLayout
@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 import androidx.wear.compose.material.Text 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 |
contentBuilder: CurvedScope.() -> Unit |
Specifies the content of this layout, currently there are 5 available elements defined in foundations for this DSL: the sub-layouts |
HierarchicalFocusCoordinator
@Composable
funHierarchicalFocusCoordinator(
requiresFocus: () -> Boolean,
content: @Composable () -> Unit
): Unit
ScrollInfoProvider
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.
ScrollInfoProvider
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 |
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.
ScrollInfoProvider
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 |
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.
SwipeToReveal
@ExperimentalWearFoundationApi
@Composable
funSwipeToReveal(
primaryAction: @Composable () -> Unit,
modifier: Modifier = Modifier,
onFullSwipe: () -> Unit = {},
state: RevealState = rememberRevealState(),
secondaryAction: (@Composable () -> Unit)? = null,
undoAction: (@Composable () -> Unit)? = null,
gestureInclusion: GestureInclusion = SwipeToRevealDefaults.gestureInclusion(state = state),
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.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.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() val coroutineScope = rememberCoroutineScope() SwipeToReveal( state = state, primaryAction = { Box( modifier = Modifier.fillMaxSize().clickable { /* Add the primary action */ coroutineScope.launch { state.animateTo(RevealValue.RightRevealed) } }, contentAlignment = Alignment.Center, ) { Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete") } }, undoAction = { Chip( modifier = Modifier.fillMaxWidth(), onClick = { /* Add the undo action */ coroutineScope.launch { state.animateTo(RevealValue.Covered) } }, colors = ChipDefaults.secondaryChipColors(), label = { Text(text = "Undo") }, ) }, ) { Chip( modifier = Modifier.fillMaxWidth().semantics { // Use custom actions to make the primary and secondary actions accessible customActions = listOf( CustomAccessibilityAction("Delete") { /* Add the primary action click handler */ true } ) }, onClick = { /* the click action associated with chip */ }, colors = ChipDefaults.secondaryChipColors(), label = { Text(text = "Swipe Me") }, ) }
Example of SwipeToReveal using RevealState 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.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row 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.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment 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.RevealValue 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() val coroutineScope = rememberCoroutineScope() SwipeToReveal( state = state, primaryAction = { Row( modifier = Modifier.fillMaxSize().clickable { /* Add the primary action */ coroutineScope.launch { state.animateTo(RevealValue.RightRevealed) } }, horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete") if (abs(state.offset) > state.revealThreshold) { // 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 the undo action */ coroutineScope.launch { state.animateTo(RevealValue.Covered) } }, colors = ChipDefaults.secondaryChipColors(), label = { Text(text = "Undo") }, ) }, ) { Chip( modifier = Modifier.fillMaxWidth().semantics { // Use custom actions to make the primary and secondary actions accessible customActions = listOf( CustomAccessibilityAction("Delete") { /* Add the primary action click handler */ true } ) }, 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( 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().semantics { // Use custom actions to make the primary and secondary actions // accessible customActions = listOf( CustomAccessibilityAction("Delete") { /* Add the primary action click handler */ coroutineScope.launch { revealState.animateTo(RevealValue.RightRevealed) } true }, CustomAccessibilityAction("More Options") { /* Add the secondary action click handler */ true }, ) }, onClick = { /* the click action associated with chip */ }, colors = ChipDefaults.secondaryChipColors(), label = { Text(text = "Swipe Me") }, ) } } } } }
| Parameters | |
|---|---|
primaryAction: @Composable () -> 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 |
onFullSwipe: () -> Unit = {} |
An optional lambda which will be triggered when a full swipe from either of the anchors is performed. |
state: RevealState = rememberRevealState() |
The |
secondaryAction: (@Composable () -> Unit)? = null |
An optional action that can be added to the component. We strongly recommend triggering the action when it is clicked. |
undoAction: (@Composable () -> Unit)? = null |
The optional undo action that will be applied to the component once the the |
gestureInclusion: GestureInclusion = SwipeToRevealDefaults.gestureInclusion(state = state) |
Provides fine-grained control so that touch gestures can be excluded when they start in a certain region. An instance of |
content: @Composable () -> Unit |
The content that will be initially displayed over the other actions provided. Custom accessibility actions should always be added to the content using Modifier.semantics - examples are shown in the code samples. |
createRevealAnchors
@ExperimentalWearFoundationApi
funcreateRevealAnchors(
coveredAnchor: Float = 0.0f,
revealingAnchor: Float = SwipeToRevealDefaults.RevealingRatio,
revealedAnchor: Float = 1.0f,
revealDirection: RevealDirection = RevealDirection.RightToLeft
): Map<RevealValue, Float>
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 |
revealingAnchor: Float = SwipeToRevealDefaults.RevealingRatio |
Anchor for the |
revealedAnchor: Float = 1.0f |
Anchor for the |
revealDirection: RevealDirection = RevealDirection.RightToLeft |
The direction in which the content can be swiped. It's strongly advised to keep the default |
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 |
collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec |
The |
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 |
collapseAnimationSpec: AnimationSpec<Float> = ExpandableItemsDefaults.collapseAnimationSpec |
The |
rememberRevealState
@ExperimentalWearFoundationApi
@Composable
funrememberRevealState(
initialValue: RevealValue = RevealValue.Covered,
animationSpec: AnimationSpec<Float> = SwipeToRevealDefaults.AnimationSpec,
confirmValueChange: (RevealValue) -> Boolean = { true },
positionalThreshold: (totalDistance: Float) -> Float = SwipeToRevealDefaults.PositionalThreshold,
anchors: Map<RevealValue, Float> = createRevealAnchors()
): RevealState
Create and remember a RevealState.
| Parameters | |
|---|---|
initialValue: RevealValue = RevealValue.Covered |
The initial value of the |
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: (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<RevealValue, Float> = createRevealAnchors() |
A map of |
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<Float, Color>,
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 import androidx.wear.compose.material.Text 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), ) }
angularGradientBackground
fun CurvedModifier.angularGradientBackground(
colors: List<Color>,
cap: StrokeCap = StrokeCap.Butt
): CurvedModifier
Specifies a sweep gradient background for a curved element.
angularSize
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. |
angularSizeDp
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 import androidx.wear.compose.material.Text 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. |
background
fun CurvedModifier.background(color: Color, cap: StrokeCap = StrokeCap.Butt): CurvedModifier
Specified a solid background for a curved element.
basicCurvedText
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 import androidx.wear.compose.material.Text 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 |
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 |
overflow: TextOverflow = TextOverflow.Clip |
How visual overflow should be handled. Note that this takes into account only explicit size curved modifiers in this element, to size this element matching the parent's, add a CurvedModifier.weight here. |
style: @Composable () -> CurvedTextStyle = { CurvedTextStyle() } |
A @Composable factory to provide the style to use. This composable SHOULDN'T generate any compose nodes. |
basicCurvedText
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 import androidx.wear.compose.material.Text 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 |
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 |
overflow: TextOverflow = TextOverflow.Clip |
How visual overflow should be handled. |
clearAndSetSemantics
fun CurvedModifier.clearAndSetSemantics(properties: CurvedSemanticsScope.() -> Unit): CurvedModifier
Allow specifying semantic properties on a curved component, and clearing the existing properties. Note that currently only contentDescription and traversalIndex are supported, and they can be applied to curved text and curvedComposable
Sample for clearing semantics:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.traversalIndex import androidx.compose.ui.text.TextStyle 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.basicCurvedText import androidx.wear.compose.foundation.clearAndSetSemantics import androidx.wear.compose.foundation.semantics import androidx.wear.compose.material.Text val style = CurvedTextStyle( letterSpacing = 0.6.sp, letterSpacingCounterClockwise = 1.4.sp, color = Color.White, ) Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CurvedLayout(modifier = Modifier.fillMaxSize()) { basicCurvedText("This is not announced", style, CurvedModifier.clearAndSetSemantics {}) } Row { Text("This is announced", Modifier.semantics { traversalIndex = -1f }) } }
| Parameters | |
|---|---|
properties: CurvedSemanticsScope.() -> Unit |
The properties to apply, |
curvedBox
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.Alignment 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 |
radialAlignment: CurvedAlignment.Radial? = null |
Radial alignment specifies where to lay down children that are thinner than the CurvedBox, either closer to the center |
angularAlignment: CurvedAlignment.Angular? = null |
Angular alignment specifies where to lay down children that are thinner than the CurvedBox, either at the |
contentBuilder: CurvedScope.() -> Unit |
Specifies the content of this layout, currently there are 5 available elements defined in foundation for this DSL: the sub-layouts |
curvedColumn
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.Row 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.Alignment 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 import androidx.wear.compose.material.Text 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 |
radialDirection: CurvedDirection.Radial? = null |
Order to lay out components, outside in or inside out. The default is to inherit from the containing |
angularAlignment: CurvedAlignment.Angular? = null |
Angular alignment specifies where to lay down children that are thinner than the curved column, either at the |
contentBuilder: CurvedScope.() -> Unit |
Scope used to provide the content for this column. |
curvedComposable
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 |
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 |
curvedRow
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.Row 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.Alignment 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 import androidx.wear.compose.material.Text 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 |
radialAlignment: CurvedAlignment.Radial? = null |
Radial alignment specifies where to lay down children that are thinner than the CurvedRow, either closer to the center |
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 |
contentBuilder: CurvedScope.() -> Unit |
Scope used to provide the content for this row. |
edgeSwipeToDismiss
fun Modifier.edgeSwipeToDismiss(
swipeToDismissBoxState: SwipeToDismissBoxState,
edgeWidth: Dp = SwipeToDismissBoxDefaults.EdgeWidth
): Modifier
Handles swipe to dismiss from the edge of the viewport.
Used when the content of the BasicSwipeToDismissBox is handling all the gestures of the viewport, which prevents BasicSwipeToDismissBox from handling the swipe-to-dismiss gesture. Examples of this scenario are horizontal paging, such as 2-d scrolling a Map or swiping horizontally between pages.
Use of Modifier.edgeSwipeToDismiss defines a zone on the left side of the viewport of width edgeWidth in which the swipe-right gesture is intercepted. Other touch events are 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. As such, Modifier.edgeSwipeToDismiss is also compatible with SwipeDismissableNavHost up to and including API 35. However, for API 36 onwards, SwipeDismissableNavHost uses platform predictive back events for navigation, and is not compatible with Modifier.edgeSwipeToDismiss.
Requires that the element to which this modifier is applied notifies the nested scroll system about the scrolling events that are happening on the element. For example, using a NestedScrollDispatcher.
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 |
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 |
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 |
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 |
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 |
hierarchicalFocusGroup
fun Modifier.hierarchicalFocusGroup(active: Boolean): Modifier
hierarchicalFocusGroup is used to annotate composables in an application, so we can keep track of what is the active part of the composition. In turn, this is used to coordinate focus in a declarative way, requesting focus when needed, as the user navigates through the app (such as between screens or between pages within a screen). In most cases, this is automatically handled by Wear Compose components and no action is necessary. In particular this is done by BasicSwipeToDismissBox, HorizontalPager, VerticalPager and PickerGroup. This modifier is useful if you implement a custom component that needs to direct focus to one of several children, like a custom Pager, a Tabbed layout, etc.
hierarchicalFocusGroups can be nested to form a focus tree, with an implicit root. For sibling hierarchicalFocusGroups, only one should have active = true. Within the focus tree, components that need to request focus can do so using Modifier.requestFocusOnHierarchyActive. Note that ScalingLazyColumn and TransformingLazyColumn are using it already, so there is no need to add it explicitly.
When focus changes, the focus tree is examined and the topmost (closest to the root of the tree) requestFocusOnHierarchyActive which has all its hierarchicalFocusGroup ancestors with active = true will request focus. If no such requestFocusOnHierarchyActive exists, the focus will be cleared.
NOTE: This shouldn't be used together with FocusRequester.requestFocus calls in LaunchedEffect.
Example usage:
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background 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.mutableIntStateOf 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.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.hierarchicalFocusGroup import androidx.wear.compose.foundation.requestFocusOnHierarchyActive var selected by remember { mutableIntStateOf(0) } Row(Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) { repeat(5) { colIx -> Box( Modifier.hierarchicalFocusGroup(active = selected == colIx) .weight(1f) .clickable { selected = colIx } .then( if (selected == colIx) { Modifier.border(BorderStroke(2.dp, Color.Red)) } else { Modifier } ) ) { // This is used a Gray background to the currently focused item, as seen by the // focus system. var focused by remember { mutableStateOf(false) } BasicText( "$colIx", style = TextStyle( color = Color.White, fontSize = 20.sp, textAlign = TextAlign.Center, ), modifier = Modifier.fillMaxWidth() .requestFocusOnHierarchyActive() .onFocusChanged { focused = it.isFocused } .focusable() .then( if (focused) { Modifier.background(Color.Gray) } else { Modifier } ), ) } } }
Sample using nested hierarchicalFocusGroup:
import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column 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.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp import androidx.wear.compose.foundation.hierarchicalFocusGroup import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.requestFocusOnHierarchyActive Column(Modifier.fillMaxSize()) { var selectedRow by remember { mutableIntStateOf(0) } repeat(2) { rowIx -> Row( Modifier.weight(1f) .fillMaxWidth() .hierarchicalFocusGroup(active = selectedRow == rowIx) ) { var selectedItem by remember { mutableIntStateOf(0) } repeat(2) { itemIx -> Box( Modifier.weight(1f).hierarchicalFocusGroup(active = selectedItem == itemIx) ) { // ScalingLazyColumn uses requestFocusOnHierarchyActive internally ScalingLazyColumn( Modifier.fillMaxWidth().clickable { selectedRow = rowIx selectedItem = itemIx } ) { val prefix = (rowIx * 2 + itemIx + 'A'.code).toChar() items(20) { BasicText( "$prefix $it", style = TextStyle( color = Color.White, fontSize = 20.sp, textAlign = TextAlign.Center, ), ) } } } } } } }
| Parameters | |
|---|---|
active: Boolean |
Pass true when this sub tree of the focus tree is active and may require the focus - otherwise, pass false. For example, a pager can apply this modifier to each page's content with a call to |
padding
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. |
padding
fun CurvedModifier.padding(paddingValues: ArcPaddingValues): CurvedModifier
Apply additional space along the edges of the content.
| Parameters | |
|---|---|
paddingValues: ArcPaddingValues |
The |
padding
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.
padding
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.
radialGradientBackground
fun CurvedModifier.radialGradientBackground(
vararg colorStops: Pair<Float, Color>,
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 import androidx.wear.compose.material.Text 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), ) }
radialGradientBackground
fun CurvedModifier.radialGradientBackground(
colors: List<Color>,
cap: StrokeCap = StrokeCap.Butt
): CurvedModifier
Specifies a radial gradient background for a curved element.
radialSize
fun CurvedModifier.radialSize(thickness: Dp): CurvedModifier
Specify the radialSize (thickness) for the content.
| Parameters | |
|---|---|
thickness: Dp |
Indicates the thickness of the content. |
requestFocusOnHierarchyActive
fun Modifier.requestFocusOnHierarchyActive(): Modifier
This Modifier is used in conjunction with hierarchicalFocusGroup and will request focus on the following focusable element when needed (i.e. this needs to be before that element in the Modifier chain). The focusable element is usually a Modifier.rotaryScrollable (or, in some rarer cases a Modifier.focusable or Modifier.focusTarget)
Multiple requestFocusOnHierarchyActive Modifiers shouldn't be siblings, in those cases they need to surround each with a hierarchicalFocusGroup, and at most one of them should have active = true, to inform which requestFocusOnHierarchyActive should get the focus.
NOTE: This shouldn't be used together with FocusRequester.requestFocus calls in LaunchedEffect.
Example usage:
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background 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.mutableIntStateOf 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.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.hierarchicalFocusGroup import androidx.wear.compose.foundation.requestFocusOnHierarchyActive var selected by remember { mutableIntStateOf(0) } Row(Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) { repeat(5) { colIx -> Box( Modifier.hierarchicalFocusGroup(active = selected == colIx) .weight(1f) .clickable { selected = colIx } .then( if (selected == colIx) { Modifier.border(BorderStroke(2.dp, Color.Red)) } else { Modifier } ) ) { // This is used a Gray background to the currently focused item, as seen by the // focus system. var focused by remember { mutableStateOf(false) } BasicText( "$colIx", style = TextStyle( color = Color.White, fontSize = 20.sp, textAlign = TextAlign.Center, ), modifier = Modifier.fillMaxWidth() .requestFocusOnHierarchyActive() .onFocusChanged { focused = it.isFocused } .focusable() .then( if (focused) { Modifier.background(Color.Gray) } else { Modifier } ), ) } } }
semantics
fun CurvedModifier.semantics(properties: CurvedSemanticsScope.() -> Unit): CurvedModifier
Allow specifying semantic properties on a curved component. Note that currently only contentDescription and traversalIndex are supported, and they can be applied to curved text and curvedComposable
Sample for setting content description and traversal order:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row 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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.traversalIndex 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.semantics import androidx.wear.compose.foundation.size import androidx.wear.compose.material.Text val style = CurvedTextStyle( letterSpacing = 0.6.sp, letterSpacingCounterClockwise = 1.4.sp, color = Color.White, ) Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CurvedLayout(modifier = Modifier.fillMaxSize()) { basicCurvedText( "2 - Left", style, CurvedModifier.semantics { contentDescription = "Left" traversalIndex = 2f }, ) curvedComposable { Box(Modifier.padding(5.dp).background(Color.Red).size(5.dp)) } basicCurvedText( "3 - Right", style, CurvedModifier.semantics { contentDescription = "Right" traversalIndex = 3f }, ) } Row { Text("Text 1", Modifier.semantics { traversalIndex = 1f }) Spacer(Modifier.size(10.dp)) Text("Text 4", Modifier.semantics { traversalIndex = 4f }) } }
| Parameters | |
|---|---|
properties: CurvedSemanticsScope.() -> Unit |
The properties to apply, |
size
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 import androidx.wear.compose.material.Text 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. |
sizeIn
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. |
weight
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.Row 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 import androidx.wear.compose.material.Text 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 LocalReduceMotion: ProvidableCompositionLocal<Boolean>
CompositionLocal for global reduce-motion setting, which turns off animations and screen movements. To use, call LocalReduceMotion.current, which returns a Boolean.
LocalScreenIsActive
val LocalScreenIsActive: ProvidableCompositionLocal<Boolean>
CompositionLocal used to express/determine if a screen is active, as specified by each component (for example, it could be updated when the user is in the middle of the gesture to switch screens, or after the gesture is done). Components that manage multiple screens (like pager and swipe to dismiss) provide this, and can be used at the screen level to update the UI or perform optimizations on inactive screens.
Defaults to true
LocalSwipeToDismissBackgroundScrimColor
val LocalSwipeToDismissBackgroundScrimColor: ProvidableCompositionLocal<Color>
CompositionLocal containing the background scrim color of BasicSwipeToDismissBox.
Defaults to Color.Black if not explicitly set.
LocalSwipeToDismissContentScrimColor
val LocalSwipeToDismissContentScrimColor: ProvidableCompositionLocal<Color>
CompositionLocal containing the content scrim color of BasicSwipeToDismissBox.
Defaults to Color.Black if not explicitly set.