androidx.wear.compose.material3
Interfaces
ButtonGroupScope |
|
MotionScheme |
A motion scheme provides all the |
PickerScope |
Receiver scope which is used by |
SurfaceTransformation |
Object to be used to apply different transformation to the content and the container (i.e. the background) of the composable. |
TimeSource |
Classes
AngularDirection |
Class to define angular direction - Clockwise and Counter Clockwise. |
AnimatedTextFontRegistry |
Generates fonts to be used by |
ButtonColors |
Represents the container and content colors used in buttons in different states. |
CardColors |
Represents Colors used in |
CheckboxButtonColors |
Represents the different container and content colors used for |
ColorScheme |
A |
ConfirmationDialogColors |
Represents the colors used in |
DatePickerColors |
Colors for |
DatePickerType |
Specifies the types of columns to display in the DatePicker. |
EdgeButtonSize |
Size of the |
IconButtonColors |
Represents the container and content colors used in an icon button in different states. |
IconButtonShapes |
Represents the shapes used for |
IconToggleButtonColors |
Represents the different container and content colors used for |
IconToggleButtonShapes |
Represents the shapes used for |
LevelIndicatorColors |
Represents the indicator and track colors used in |
OpenOnPhoneDialogColors |
Represents the colors used in |
PagerSensitivity |
Represents the sensitivity level of pager for snapping algorithms, such as during fling or rotary scrolling (either horizontal or vertical). |
PickerGroupScope |
|
PickerState |
A state object that can be hoisted to observe item selection. |
PlaceholderState |
A state object that can be used to control placeholders. |
ProgressIndicatorColors |
Represents the indicator and track colors used in progress indicator. |
RadioButtonColors |
Represents the different container and content colors used for |
RevealDirection |
Different values |
RevealState |
A class to keep track of the state of the composable. |
RevealValue |
Different values that determine the state of the |
ScreenStage |
|
ScrollIndicatorColors |
Represents the indicator and track colors used in |
Shapes |
Material surfaces can be displayed in different shapes. |
SliderColors |
Represents the background and content colors used in |
SplitCheckboxButtonColors |
Represents the different colors used in |
SplitRadioButtonColors |
Represents the different colors used in |
SplitSwitchButtonColors |
Represents the different colors used in |
StepperColors |
Represents Colors used in |
SwipeToRevealScope |
Scope for the actions of a |
SwitchButtonColors |
Represents the different container and content colors used for |
TextButtonColors |
Represents the container and content colors used in a text button in different states. |
TextButtonShapes |
Represents the shapes used for |
TextConfiguration |
Class representing aspects of |
TextToggleButtonColors |
Represents the different container and content colors used for |
TextToggleButtonShapes |
Represents the shapes used for |
TimePickerColors |
Represents the colors used by a |
TimePickerSelection |
|
TimePickerType |
Specifies the types of columns to display in the TimePicker. |
Typography |
Class holding typography definitions as defined by the Wear Material typography specification. |
Objects
AlertDialogDefaults |
Contains the default values used by |
AnimatedTextDefaults |
Defaults for AnimatedText. |
ArcProgressIndicatorDefaults |
Contains default values for |
ButtonDefaults |
Contains the default values used by |
ButtonGroupDefaults |
Contains the default values used by |
CardDefaults |
Contains the default values used by |
CheckboxButtonDefaults |
Contains the default values used by |
CircularProgressIndicatorDefaults |
Contains default values for |
ConfirmationDialogDefaults |
Contains default values used by |
CurvedTextDefaults |
|
DatePickerDefaults |
Contains the default values used by |
EdgeButtonDefaults |
Contains the default values used by |
FadingExpandingLabelDefaults |
Contains default values for |
IconButtonDefaults |
Contains the default values used by |
IconToggleButtonDefaults |
Contains the default values used by |
LevelIndicatorDefaults |
Contains the default values used for |
LinearProgressIndicatorDefaults |
Contains defaults for Linear Progress Indicator. |
ListHeaderDefaults |
|
MaterialTheme |
|
OpenOnPhoneDialogDefaults |
Contains the default values used by |
PageIndicatorDefaults |
Contains the default values used by |
PagerScaffoldDefaults |
Contains default values used for |
PickerDefaults |
Contains the default values used by |
PlaceholderDefaults |
Contains the default values used for providing placeholders. |
ProgressIndicatorDefaults |
Contains defaults for Progress Indicators. |
RadioButtonDefaults |
Contains the default values used by |
ScreenScaffoldDefaults |
Contains the default values used by |
ScrollIndicatorDefaults |
Contains the default values used for |
ShapeDefaults |
Contains the default values used by |
SliderDefaults |
Defaults used by slider. |
StepperDefaults |
Defaults used by |
SwipeToRevealDefaults |
Defaults for Material 3 |
SwitchButtonDefaults |
Contains the default values used by |
TextButtonDefaults |
Contains the default values used by |
TextConfigurationDefaults |
Default values for |
TextToggleButtonDefaults |
Contains the default values used by |
TimePickerDefaults |
Contains the default values used by |
TimeTextDefaults |
Contains the default values used by |
Top-level functions summary
Unit |
@ComposableDialogs provide important prompts in a user flow. |
Unit |
@ComposableDialogs provide important prompts in a user flow. |
Unit |
@ComposableAlertDialogs provide important prompts in a user flow. |
Unit |
@ComposableThis |
Unit |
@ComposableThis |
Unit |
@ComposableThis |
Unit |
@ComposableAnimates a page within a Pager with a scaling and scrim effect based on its position. |
Unit |
@ComposableA composable that displays an animated text. |
Unit |
@ComposableOpinionated Wear Material 3 |
Unit |
@ComposableOpinionated Wear Material 3 |
Unit |
@Composable
|
Unit |
@ComposableIndeterminate Material Design arc progress indicator. |
Unit |
@ComposableBase level Wear Material3 |
Unit |
@ComposableBase level Wear Material3 |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableLayout component to implement an expressive group of buttons in a row, that react to touch by growing the touched button, (while the neighbor(s) shrink to accommodate and keep the group width constant). |
Unit |
@ComposableBase level Wear Material 3 |
Unit |
@ComposableWear Material 3 |
Unit |
@ComposableBase level Wear Material 3 |
Unit |
@ComposableWear Material 3 |
Unit |
@ComposableThe Wear Material |
Unit |
@ComposableBase level Wear Material3 |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableIndeterminate Material Design circular progress indicator. |
Unit |
@ComposableMaterial Design circular progress indicator. |
Unit |
@ComposableA Wear Material3 |
Unit |
@ComposableShows a transient |
Unit |
@ComposableShows a transient |
Unit |
@ComposableThis overload of |
Unit |
@ComposableThis overload of |
Unit |
@RequiresApi(value = 26)Full screen |
Unit |
@ComposableA base dialog component used by |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableAnimates label text for which the number of lines can vary, changing the size of the container component. |
Unit |
@ComposableShows a |
Unit |
@Composable
|
Unit |
@ComposableWear Material |
Unit |
@ComposableBase level Wear Material3 |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableWear Material |
Unit |
@ComposableHorizontal page indicator for use with |
Unit |
@Composable
|
Unit |
@ComposableIcon component that draws |
Unit |
@ComposableIcon component that draws |
Unit |
Icon component that draws a |
Unit |
@ComposableWear Material |
Unit |
@ComposableWear Material |
Unit |
@ComposableCreates a |
Unit |
@ComposableMaterial Design linear progress indicator. |
Unit |
@ComposableA slot based composable for creating a list header item. |
Unit |
@ComposableA two slot based composable for creating a list sub-header item. |
Unit |
@ComposableMaterialTheme defines the styling principles from the Wear Material3 design specification which extends the Material design specification. |
Unit |
@ComposableA full-screen dialog that displays an animated icon with a curved text at the bottom. |
Unit |
@ComposableThis composable provides the content for an |
Unit |
@ComposableBase level Wear Material3 |
Unit |
@ComposableWear Material3 |
Unit |
@ComposableOutlined Wear Material 3 |
Unit |
@ComposableOutlined Wear Material 3 |
Unit |
@ComposableWear Material |
Unit |
@ComposableA scrollable list of items to pick from. |
Unit |
@ComposableA group of |
Unit |
@ComposableThis function is used to set the current value of |
Unit |
@ComposableThe Wear Material |
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@ComposableA composable that displays a visual indicator of scrolling progress within a scrollable container. |
Unit |
@ComposableA composable that displays a visual indicator of scrolling progress within a scrollable container. |
Unit |
@ComposableA composable that displays a visual indicator of scrolling progress within a scrollable container. |
Unit |
@ComposableA composable that displays a visual indicator of scrolling progress within a scrollable container. |
Unit |
@ComposableMaterial Design segmented circular progress indicator. |
Unit |
@ComposableMaterial Design segmented circular progress indicator. |
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@ComposableThe Wear Material |
Unit |
@ComposableThe Wear Material |
Unit |
@ComposableThe Wear Material |
Unit |
@Composable
|
Unit |
@Composable
|
Unit |
@ComposableCreates a |
Unit |
@ComposableCreates a |
Unit |
@ComposableShows a |
Unit |
@Composable
|
Unit |
@ComposableWear Material 3 |
Unit |
@ComposableWear Material 3 |
Unit |
@Composable
|
Unit |
@ComposableThe Wear Material |
Unit |
@ComposableHigh level element that displays text and provides semantics / accessibility information. |
Unit |
@ComposableHigh level element that displays text and provides semantics / accessibility information. |
Unit |
@ComposableWear Material |
Unit |
@ComposableWear Material |
Unit |
@RequiresApi(value = 26)A full screen TimePicker with configurable columns that allows users to select a time. |
Unit |
@ComposableLayout to show the current time and a label, they will be drawn in a curve, following the top edge of the screen. |
Unit |
@ComposableOpinionated Wear Material 3 |
Unit |
@ComposableThis |
Unit |
@ComposableOpinionated Wear Material 3 |
Unit |
@ComposableThis |
Unit |
@ComposableVertical page indicator for use with |
Unit |
@Composable
|
Color |
@ComposableThe Material color system contains pairs of colors that are typically used for the background and content color inside a component. |
ColorScheme? |
dynamicColorScheme(context: Context)Creates a dynamic color scheme. |
AnimatedTextFontRegistry |
@ComposableGenerates an |
PickerState |
@ComposableCreates a |
PlaceholderState |
@ComposableCreates a |
RevealState |
@ComposableCreate and |
IndicationNodeFactory |
Creates a Ripple using the provided values and values inferred from the theme. |
IndicationNodeFactory |
ripple(color: ColorProducer, bounded: Boolean, radius: Dp)Creates a Ripple using the provided values and values inferred from the theme. |
Extension functions summary
SurfaceTransformation |
Exposes |
Unit |
CurvedScope.confirmationDialogCurvedText(A customized variation of |
Color |
ColorScheme.contentColorFor(backgroundColor: Color)The Material color system contains pairs of colors that are typically used for the background and content color inside a component. |
Unit |
CurvedScope.curvedText(CurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen). |
Unit |
DrawScope.drawCircularProgressIndicator(Draw a simple non-animating circular progress indicator. |
Modifier |
Reserves at least 48.dp in size to disambiguate touch interactions if the element would measure smaller. |
Unit |
CurvedScope.openOnPhoneDialogCurvedText(A customized variation of |
Modifier |
@ComposableModifier.placeholder draws a skeleton shape over a component, for situations when no provisional content (such as cached data) is available. |
Modifier |
@ComposableModifier.placeholderShimmer draws a periodic shimmer over content, indicating to the user that contents are loading or potentially out of date. |
Modifier |
Modifier.rangeSemantics(Modifier to add semantics signifying progress of the Stepper/Slider. |
Modifier |
Modifier.scrollAway(Scroll an item vertically in/out of view based on scroll state provided by a scrolling list. |
Unit |
CurvedScope.timeTextCurvedText(time: String, style: CurvedTextStyle?)Default curved text to use in a |
Unit |
CurvedScope.timeTextSeparator(A default implementation of Separator, to be shown between any text/composable and the time. |
Modifier |
Modifier.touchTargetAwareSize(size: Dp)Modifier to set both the size and recommended touch target for |
Top-level properties summary
ProvidableCompositionLocal<Color> |
CompositionLocal containing the preferred content color for a given position in the hierarchy. |
ProvidableCompositionLocal<TextConfiguration> |
CompositionLocal containing the preferred |
ProvidableCompositionLocal<TextStyle> |
CompositionLocal containing the preferred |
Top-level functions
AlertDialog
@Composable
fun AlertDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.contentWithIconPadding() } else { AlertDialogDefaults.contentPadding() },
properties: DialogProperties = DialogProperties(),
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The dialog is scrollable by default if the content exceeds the viewport height.
This overload doesn't have any dedicated slots for buttons. It has a content slot so that the caller has flexibility in how to seek user input. In most cases, we recommend using other AlertDialog variations with 2 confirm/dismiss buttons or a single confirmation button.
Where user input is not required, such as displaying a transient success or failure message, use ConfirmationDialog, SuccessConfirmationDialog or FailureConfirmationDialog instead.
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed by swiping to the right or by other dismiss action. Implementation of this lambda must remove the dialog from the composition hierarchy e.g. by setting |
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.contentWithIconPadding()
} else {
AlertDialogDefaults.contentPadding()
} |
The padding to apply around the entire dialog's contents. It is recommended to use the defaults, which adjust to reduce the top padding when an icon is present. |
properties: DialogProperties = DialogProperties() |
An optional |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AlertDialog
@Composable
fun AlertDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
edgeButton: @Composable BoxScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.contentWithIconPadding() } else { AlertDialogDefaults.contentPadding() },
properties: DialogProperties = DialogProperties(),
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The dialog is scrollable by default if the content exceeds the viewport height.
This overload has a single slot for a confirm EdgeButton at the bottom of the dialog. It should be used when the user will be presented with a single acknowledgement.
Where user input is not required, such as displaying a transient success or failure message, use ConfirmationDialog, SuccessConfirmationDialog or FailureConfirmationDialog instead.
Example of an AlertDialog with an icon, title, text and bottom EdgeButton:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.AccountCircle import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.AlertDialog import androidx.wear.compose.material3.AlertDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text var showDialog by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showDialog = true }, label = { Text("Show Dialog") }, ) } AlertDialog( visible = showDialog, onDismissRequest = { showDialog = false }, icon = { Icon( Icons.Rounded.AccountCircle, modifier = Modifier.size(32.dp), contentDescription = null, tint = MaterialTheme.colorScheme.primary, ) }, title = { Text("Mobile network is not currently available") }, edgeButton = { AlertDialogDefaults.EdgeButton( onClick = { // Perform confirm action here showDialog = false } ) }, )
Example of an AlertDialog with content groups and a bottom EdgeButton:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.AlertDialog import androidx.wear.compose.material3.AlertDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.SwitchButton import androidx.wear.compose.material3.Text var showDialog by remember { mutableStateOf(false) } var weatherEnabled by remember { mutableStateOf(false) } var calendarEnabled by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showDialog = true }, label = { Text("Show Dialog") }, ) } AlertDialog( visible = showDialog, onDismissRequest = { showDialog = false }, title = { Text("Share your location") }, text = { Text(" The following apps have asked you to share your location") }, edgeButton = { AlertDialogDefaults.EdgeButton( onClick = { // Perform confirm action here showDialog = false } ) { Text("Share once") } }, ) { item { SwitchButton( modifier = Modifier.fillMaxWidth(), checked = weatherEnabled, onCheckedChange = { weatherEnabled = it }, label = { Text("Weather") }, ) } item { SwitchButton( modifier = Modifier.fillMaxWidth(), checked = calendarEnabled, onCheckedChange = { calendarEnabled = it }, label = { Text("Calendar") }, ) } item { AlertDialogDefaults.GroupSeparator() } item { FilledTonalButton( modifier = Modifier.fillMaxWidth(), onClick = {}, label = { Text(modifier = Modifier.fillMaxWidth(), text = "Never share") }, ) } item { FilledTonalButton( modifier = Modifier.fillMaxWidth(), onClick = {}, label = { Text(modifier = Modifier.fillMaxWidth(), text = "Share always") }, ) } }
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed by swiping to the right or by other dismiss action. Implementation of this lambda must remove the dialog from the composition hierarchy e.g. by setting |
edgeButton: @Composable BoxScope.() -> Unit |
Slot for an |
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text.By default, |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.contentWithIconPadding()
} else {
AlertDialogDefaults.contentPadding()
} |
The padding to apply around the entire dialog's contents. Bottom padding will be ignored and default spacing for the |
properties: DialogProperties = DialogProperties() |
An optional |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AlertDialog
@Composable
fun AlertDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
confirmButton: @Composable RowScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
dismissButton: @Composable RowScope.() -> Unit = { AlertDialogDefaults.DismissButton(onDismissRequest) },
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.confirmDismissWithIconContentPadding() } else { AlertDialogDefaults.confirmDismissContentPadding() },
properties: DialogProperties = DialogProperties(),
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
AlertDialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The AlertDialog is scrollable by default if the content exceeds the viewport height.
This overload has 2 IconButtons for confirmation and cancellation, placed horizontally at the bottom of the dialog. It should be used when the user will be presented with a binary decision, to either confirm or dismiss an action.
Where user input is not required, such as displaying a transient success or failure message, use ConfirmationDialog, SuccessConfirmationDialog or FailureConfirmationDialog instead.
Example of an AlertDialog with an icon, title and two buttons to confirm and dismiss:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.AccountCircle import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.AlertDialog import androidx.wear.compose.material3.AlertDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text var showDialog by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showDialog = true }, label = { Text("Show Dialog") }, ) } AlertDialog( visible = showDialog, onDismissRequest = { showDialog = false }, icon = { Icon( Icons.Rounded.AccountCircle, modifier = Modifier.size(32.dp), contentDescription = null, tint = MaterialTheme.colorScheme.primary, ) }, title = { Text("Enable Battery Saver Mode?") }, text = { Text("Your battery is low. Turn on battery saver.") }, confirmButton = { AlertDialogDefaults.ConfirmButton( onClick = { // Perform confirm action here showDialog = false } ) }, dismissButton = { AlertDialogDefaults.DismissButton( onClick = { // Perform dismiss action here showDialog = false } ) }, )
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed by swiping right (typically also called by the |
confirmButton: @Composable RowScope.() -> Unit |
A slot for a |
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
dismissButton: @Composable RowScope.() -> Unit = {
AlertDialogDefaults.DismissButton(onDismissRequest)
} |
A slot for a |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.confirmDismissWithIconContentPadding()
} else {
AlertDialogDefaults.confirmDismissContentPadding()
} |
The padding to apply around the entire dialog's contents. It is recommended to use the defaults, which adjust to reduce the top padding when an icon is present. |
properties: DialogProperties = DialogProperties() |
An optional |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AlertDialogContent
@Composable
fun AlertDialogContent(
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.contentWithIconPadding() } else { AlertDialogDefaults.contentPadding() },
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
This AlertDialogContent overload provides the content for an AlertDialog without any dedicated slots for buttons. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.
| Parameters | |
|---|---|
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.contentWithIconPadding()
} else {
AlertDialogDefaults.contentPadding()
} |
The padding to apply around the entire dialog's contents. It is recommended to use the defaults, which adjust to reduce the top padding when an icon is present. |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AlertDialogContent
@Composable
fun AlertDialogContent(
edgeButton: @Composable BoxScope.() -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.contentWithIconPadding() } else { AlertDialogDefaults.contentPadding() },
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
This AlertDialogContent overload provides the content for an AlertDialog with a single EdgeButton to confirm an action. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.
| Parameters | |
|---|---|
edgeButton: @Composable BoxScope.() -> Unit |
Slot for an |
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.contentWithIconPadding()
} else {
AlertDialogDefaults.contentPadding()
} |
The padding to apply around the entire dialog's contents. Bottom padding will be ignored and default spacing for the |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AlertDialogContent
@Composable
fun AlertDialogContent(
confirmButton: @Composable RowScope.() -> Unit,
title: @Composable () -> Unit,
dismissButton: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
text: (@Composable () -> Unit)? = null,
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
contentPadding: PaddingValues = if (icon != null) { AlertDialogDefaults.confirmDismissWithIconContentPadding() } else { AlertDialogDefaults.confirmDismissContentPadding() },
content: (ScalingLazyListScope.() -> Unit)? = null
): Unit
This AlertDialogContent overload provides the content for an AlertDialog with 2 buttons to confirm or dismiss an action. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.
| Parameters | |
|---|---|
confirmButton: @Composable RowScope.() -> Unit |
A slot for a |
title: @Composable () -> Unit |
A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, |
dismissButton: @Composable RowScope.() -> Unit |
A slot for a |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
icon: (@Composable () -> Unit)? = null |
Optional slot for an icon to be shown at the top of the dialog. |
text: (@Composable () -> Unit)? = null |
Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient. |
verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement |
The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this |
contentPadding: PaddingValues = if (icon != null) {
AlertDialogDefaults.confirmDismissWithIconContentPadding()
} else {
AlertDialogDefaults.confirmDismissContentPadding()
} |
The padding to apply around the entire dialog's contents. It is recommended to use the defaults, which adjust to reduce the top padding when an icon is present. |
content: (ScalingLazyListScope.() -> Unit)? = null |
A slot for additional content, displayed within a scrollable |
AnimatedPage
@Composable
fun AnimatedPage(
pageIndex: Int,
pagerState: PagerState,
contentScrimColor: Color = MaterialTheme.colorScheme.background,
content: @Composable () -> Unit
): Unit
Animates a page within a Pager with a scaling and scrim effect based on its position.
This composable applies a scaling animation and a scrim overlay to the page content, creating a visual cue for page transitions. The animation is responsive to the page's position within the Pager and adapts to the device's reduce motion settings and layout direction.
| Parameters | |
|---|---|
pageIndex: Int |
The index of the page being animated. |
pagerState: PagerState |
The |
contentScrimColor: Color = MaterialTheme.colorScheme.background |
The color of the scrim overlay applied during page transitions. Defaults to the background color of the |
content: @Composable () -> Unit |
The composable content of the page. |
AnimatedText
@Composable
@RequiresApi(value = 31)
fun AnimatedText(
text: String,
fontRegistry: AnimatedTextFontRegistry,
progressFraction: () -> Float,
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.Center
): Unit
A composable that displays an animated text.
AnimatedText can be used to animate a text along font variation axes and size. It requires an AnimatedTextFontRegistry to improve performance.
AnimatedTextFontRegistry can be generated using rememberAnimatedTextFontRegistry method, which requires start and end font variation axes, and start and end font sizes for the animation.
Start of the animation is when the animatable is at 0f and end of the animation is when the animatable is at 1f. Current animation progress is provided by the progressFraction function. This should be between 0f and 1f, but might go beyond in some cases such as overshooting spring animations.
Example of a one-shot animation with AnimatedText
import androidx.compose.animation.core.Animatable import androidx.compose.foundation.clickable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontVariation import androidx.compose.ui.unit.sp import androidx.wear.compose.material3.AnimatedText import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry val scope = rememberCoroutineScope() val animatable = remember { Animatable(0f) } val animate = { scope.launch { // Animate from 0 to 1 and then back to 0. animatable.animateTo(1f) animatable.animateTo(0f) } } val animatedTextFontRegistry = rememberAnimatedTextFontRegistry( // Variation axes at the start of the animation, width 10, weight 200 startFontVariationSettings = FontVariation.Settings(FontVariation.width(10f), FontVariation.weight(200)), // Variation axes at the end of the animation, width 100, weight 500 endFontVariationSettings = FontVariation.Settings(FontVariation.width(100f), FontVariation.weight(500)), startFontSize = 30.sp, endFontSize = 40.sp, ) AnimatedText( text = "Hello!", fontRegistry = animatedTextFontRegistry, // Content alignment anchors the animation at the vertical center, expanding horizontally contentAlignment = Alignment.CenterStart, progressFraction = { animatable.value }, modifier = Modifier.clickable(onClick = { animate() }), ) LaunchedEffect(Unit) { animate() }
Example of an animation in response to a button press with AnimatedText
import androidx.compose.animation.core.Animatable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontVariation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.wear.compose.material3.AnimatedText import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry val scope = rememberCoroutineScope() val animatedTextFontRegistry = rememberAnimatedTextFontRegistry( // Variation axes at the start of the animation, width 10, weight 200 startFontVariationSettings = FontVariation.Settings(FontVariation.width(10f), FontVariation.weight(200)), // Variation axes at the end of the animation, width 100, weight 500 endFontVariationSettings = FontVariation.Settings(FontVariation.width(100f), FontVariation.weight(500)), startFontSize = 30.sp, endFontSize = 30.sp, ) val number = remember { mutableIntStateOf(0) } val textAnimatable = remember { Animatable(0f) } Row(verticalAlignment = Alignment.CenterVertically) { Button( modifier = Modifier.padding(horizontal = 16.dp), onClick = { number.value -= 1 scope.launch { textAnimatable.animateTo(1f) textAnimatable.animateTo(0f) } }, label = { Text(modifier = Modifier.semantics { contentDescription = "Decrease" }, text = "-") }, ) AnimatedText( text = "${number.value}", fontRegistry = animatedTextFontRegistry, progressFraction = { textAnimatable.value }, ) Button( modifier = Modifier.padding(horizontal = 16.dp), onClick = { number.value += 1 scope.launch { textAnimatable.animateTo(1f) textAnimatable.animateTo(0f) } }, label = { Text(modifier = Modifier.semantics { contentDescription = "Increase" }, text = "+") }, ) }
Example showing how AnimatedTextFontRegistry can be reused and shared between two AnimatedText composables
import androidx.compose.animation.core.Animatable import androidx.compose.foundation.layout.Column import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.text.font.FontVariation import androidx.compose.ui.unit.sp import androidx.wear.compose.material3.AnimatedText import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry val animatedTextFontRegistry = rememberAnimatedTextFontRegistry( // Variation axes at the start of the animation, width 50, weight 300 startFontVariationSettings = FontVariation.Settings(FontVariation.width(50f), FontVariation.weight(300)), // Variation axes at the end of the animation are the same as the start axes endFontVariationSettings = FontVariation.Settings(FontVariation.width(50f), FontVariation.weight(300)), startFontSize = 15.sp, endFontSize = 25.sp, ) val firstAnimatable = remember { Animatable(0f) } val secondAnimatable = remember { Animatable(0f) } Column(horizontalAlignment = Alignment.CenterHorizontally) { AnimatedText( text = "Top Text", fontRegistry = animatedTextFontRegistry, progressFraction = { firstAnimatable.value }, ) AnimatedText( text = "Bottom Text", fontRegistry = animatedTextFontRegistry, progressFraction = { secondAnimatable.value }, ) } LaunchedEffect(Unit) { firstAnimatable.animateTo(1f) firstAnimatable.animateTo(0f) secondAnimatable.animateTo(1f) secondAnimatable.animateTo(0f) }
| Parameters | |
|---|---|
text: String |
The text to be displayed. |
fontRegistry: AnimatedTextFontRegistry |
The font registry to be used to animate the text. |
progressFraction: () -> Float |
A provider for the current state of the animation. Provided value should be between 0f and 1f, but might go beyond in some cases such as overshooting spring animations. |
modifier: Modifier = Modifier |
Modifier to be applied to the composable. |
contentAlignment: Alignment = Alignment.Center |
Alignment within the bounds of the Canvas. |
AppCard
@Composable
fun AppCard(
appName: @Composable RowScope.() -> Unit,
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
transformation: SurfaceTransformation? = null,
appImage: (@Composable RowScope.() -> Unit)? = null,
time: (@Composable RowScope.() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Opinionated Wear Material 3 Card that offers a specific 5 slot layout to show information about an application, e.g. a notification. AppCards are designed to show interactive elements from multiple applications. They will typically be used by the system UI, e.g. for showing a list of notifications from different applications. However it could also be adapted by individual application developers to show information about different parts of their application.
This AppCard does not handle input events - see the other AppCard overloads if you want a clickable AppCard.
The first row of the layout has three slots, 1) a small optional application Image or Icon of size CardDefaults.AppImageSizexCardDefaults.AppImageSize dp, 2) an application name (emphasised with the CardColors.appColor() color), it is expected to be a short start aligned Text composable, and 3) the time that the application activity has occurred which will be shown on the top row of the card, this is expected to be an end aligned Text composable showing a time relevant to the contents of the Card.
The second row shows a title, this is expected to be a single row of start aligned Text.
The rest of the Card contains the content which can be either Text or an Image. If the content is text it can be single or multiple line and is expected to be Top and Start aligned.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of a non-clickable AppCard:
import androidx.wear.compose.material3.AppCard import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text AppCard( appName = { Text("App name") }, title = { Text("Card title") }, time = { Text("Now") }, ) { Text("Non clickable card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
appName: @Composable RowScope.() -> Unit |
A slot for displaying the application name, expected to be a single line of start aligned text of |
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of start aligned text of |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
appImage: (@Composable RowScope.() -> Unit)? = null |
A slot for a small ( |
time: (@Composable RowScope.() -> Unit)? = null |
A slot for displaying the time relevant to the contents of the card, expected to be a short piece of end aligned text of |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
AppCard
@Composable
fun AppCard(
onClick: () -> Unit,
appName: @Composable RowScope.() -> Unit,
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
appImage: (@Composable RowScope.() -> Unit)? = null,
time: (@Composable RowScope.() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Opinionated Wear Material 3 Card that offers a specific 5 slot layout to show information about an application, e.g. a notification. AppCards are designed to show interactive elements from multiple applications. They will typically be used by the system UI, e.g. for showing a list of notifications from different applications. However it could also be adapted by individual application developers to show information about different parts of their application.
The first row of the layout has three slots, 1) a small optional application Image or Icon of size CardDefaults.AppImageSizexCardDefaults.AppImageSize dp, 2) an application name (emphasised with the CardColors.appColor() color), it is expected to be a short start aligned Text composable, and 3) the time that the application activity has occurred which will be shown on the top row of the card, this is expected to be an end aligned Text composable showing a time relevant to the contents of the Card.
The second row shows a title, this is expected to be a single row of start aligned Text.
The rest of the Card contains the content which can be either Text or an Image. If the content is text it can be single or multiple line and is expected to be Top and Start aligned.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of an AppCard with onClick:
import androidx.wear.compose.material3.AppCard import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text AppCard( onClick = { /* Do something */ }, appName = { Text("App name") }, title = { Text("Card title") }, time = { Text("Now") }, ) { Text("Card content") }
Example of an AppCard with icon:
import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.contentDescription import androidx.wear.compose.material3.AppCard import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text AppCard( onClick = { /* Do something */ }, appName = { Text("App name") }, appImage = { Icon( painter = painterResource(id = android.R.drawable.star_big_off), contentDescription = "Star icon", modifier = Modifier.size(CardDefaults.AppImageSize) .wrapContentSize(align = Alignment.Center), tint = MaterialTheme.colorScheme.primary, ) }, title = { Text("Card title") }, time = { Text("Now") }, ) { Text("Card content") }
Example of an AppCard with image content:
import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.AppCard import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text val configuration = LocalConfiguration.current // Add padding to the end of the image in order to maintain the correct proportions // between the image and the card. val imageEndPaddingDp = (0.15f * configuration.screenWidthDp).dp AppCard( onClick = { /* Do something */ }, appName = { Text("App name") }, appImage = { Icon( painter = painterResource(id = android.R.drawable.star_big_off), contentDescription = "Star icon", modifier = Modifier.size(CardDefaults.AppImageSize) .wrapContentSize(align = Alignment.Center), tint = MaterialTheme.colorScheme.primary, ) }, title = { Text("With image") }, time = { Text("Now") }, ) { Spacer(modifier = Modifier.height(4.dp)) Row(modifier = Modifier.fillMaxWidth()) { Image( modifier = Modifier.weight(1f).aspectRatio(16f / 9f).clip(RoundedCornerShape(16.dp)), painter = painterResource(id = R.drawable.card_content_image), contentScale = ContentScale.Crop, contentDescription = null, ) Spacer(modifier = Modifier.width(imageEndPaddingDp)) } }
Example of an outlined AppCard:
import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.contentDescription import androidx.wear.compose.material3.AppCard import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text AppCard( onClick = { /* Do something */ }, appName = { Text("App name") }, appImage = { Icon( Icons.Filled.Favorite, contentDescription = "Favorite icon", modifier = Modifier.size(CardDefaults.AppImageSize), ) }, title = { Text("App card") }, time = { Text("Now") }, colors = CardDefaults.outlinedCardColors(), border = CardDefaults.outlinedCardBorder(), ) { Text("Card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
appName: @Composable RowScope.() -> Unit |
A slot for displaying the application name, expected to be a single line of start aligned text of |
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of start aligned text of |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
appImage: (@Composable RowScope.() -> Unit)? = null |
A slot for a small ( |
time: (@Composable RowScope.() -> Unit)? = null |
A slot for displaying the time relevant to the contents of the card, expected to be a short piece of end aligned text of |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
AppScaffold
@Composable
fun AppScaffold(
modifier: Modifier = Modifier,
timeText: @Composable () -> Unit = { TimeText() },
containerColor: Color = MaterialTheme.colorScheme.background,
contentColor: Color = contentColorFor(containerColor),
content: @Composable BoxScope.() -> Unit
): Unit
AppScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components.
AppScaffold allows static screen elements such as TimeText to remain visible during in-app transitions such as swipe-to-dismiss. It provides a slot for the main application content, which will usually be supplied by a navigation component such as SwipeDismissableNavHost.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
The modifier for the top level of the scaffold. |
timeText: @Composable () -> Unit = { TimeText() } |
The default time (and potentially status message) to display at the top middle of the screen in this app. When |
containerColor: Color = MaterialTheme.colorScheme.background |
The container color of the app drawn behind the |
contentColor: Color = contentColorFor(containerColor) |
The content color for the application |
content: @Composable BoxScope.() -> Unit |
The main content for this application. |
ArcProgressIndicator
@Composable
fun ArcProgressIndicator(
modifier: Modifier = Modifier,
startAngle: Float = ArcProgressIndicatorDefaults.IndeterminateStartAngle,
endAngle: Float = ArcProgressIndicatorDefaults.IndeterminateEndAngle,
angularDirection: AngularDirection = AngularDirection.CounterClockwise,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth,
gapSize: Dp = ArcProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit
Indeterminate Material Design arc progress indicator.
Indeterminate progress indicator expresses an unspecified wait time and animates indefinitely. This overload provides a variation over the usual circular spinner by allowing the start and end angles to be specified.
Example of indeterminate arc progress indicator:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ArcProgressIndicator import androidx.wear.compose.material3.ArcProgressIndicatorDefaults import androidx.wear.compose.material3.ProgressIndicatorDefaults Box(modifier = Modifier.fillMaxSize()) { ArcProgressIndicator( modifier = Modifier.align(Alignment.Center) .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter) ) }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
Modifier to be applied to the ArcProgressIndicator. |
startAngle: Float = ArcProgressIndicatorDefaults.IndeterminateStartAngle |
the start angle of this progress indicator arc (specified in degrees). It is recommended to use |
endAngle: Float = ArcProgressIndicatorDefaults.IndeterminateEndAngle |
the end angle of this progress indicator arc (specified in degrees). It is recommended to use |
angularDirection: AngularDirection = AngularDirection.CounterClockwise |
Determines whether the animation is in the clockwise or counter-clockwise direction. |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth |
The stroke width for the progress indicator. The recommended value is |
gapSize: Dp = ArcProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke end caps are not included in this distance. |
Button
@Composable
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
Base level Wear Material3 Button that offers a single slot to take any content. Used as the container for more opinionated Button components that take specific content such as icons and labels.
The Button is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the Button height adjusts to accommodate the contents.
Button takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.
Other recommended buttons with ButtonColors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
Button can be enabled or disabled. A disabled button will not respond to click events.
Example of a Button:
import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Text Button(onClick = { /* Do something */ }, label = { Text("Simple Button") }, modifier = modifier)
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.buttonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the Button |
Button
@Composable
fun Button(
onClick: () -> Unit,
containerPainter: Painter,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
disabledContainerPainter: Painter = ButtonDefaults.disabledContainerPainter(containerPainter),
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.buttonWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
Base level Wear Material3 Button that offers parameters for container image backgrounds, with a single slot to take any content.
An Image background is a means to reinforce the meaning of information in a Button. Buttons should have a content color that contrasts with the background image and scrim.
This Button takes containerPainter for the image background to be drawn when the button is enabled and disabledContainerPainter for the image background when the button is disabled (The ButtonColors containerColor and disabledContainerColor properties are ignored). It is recommended to use ButtonDefaults.containerPainter to create the painters so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The Button is Stadium-shaped by default and has a max height designed to take no more than two lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the Button height adjusts to accommodate the contents.
Button can be enabled or disabled. A disabled button will not respond to click events.
Example of a Button with an image background:
import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text Button( onClick = { /* Do something */ }, containerPainter = ButtonDefaults.containerPainter( image = painterResource(id = R.drawable.backgroundimage) ), enabled = enabled, label = { Text("Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", ) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
containerPainter: Painter |
The |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
disabledContainerPainter: Painter = ButtonDefaults.disabledContainerPainter(containerPainter) |
|
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.buttonWithContainerPainterColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the Button |
Button
@Composable
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: @Composable RowScope.() -> Unit
): Unit
Wear Material3 Button that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.
The Button is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the Button height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.
If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.
Button takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.
Other recommended buttons with ButtonColors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
Button can be enabled or disabled. A disabled button will not respond to click events.
Example of a Button with an icon and secondary label:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text Button( onClick = { /* Do something */ }, label = { Text("Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, modifier = modifier, )
Example of a Button with a large icon and adjusted content padding:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text // When customising the icon size, it is recommended to also specify // the associated content padding Button( onClick = { /* Do something */ }, enabled = enabled, label = { Text("Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.LargeIconSize), ) }, contentPadding = ButtonDefaults.ButtonWithLargeIconContentPadding, modifier = modifier, )
Example of a Button with an extra large icon and adjusted content padding:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text // When customising the icon size, it is recommended to also specify // the associated content padding Button( onClick = { /* Do something */ }, enabled = enabled, label = { Text("Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.ExtraLargeIconSize), ) }, contentPadding = ButtonDefaults.ButtonWithExtraLargeIconContentPadding, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.buttonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. |
Button
@Composable
fun Button(
onClick: () -> Unit,
containerPainter: Painter,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
disabledContainerPainter: Painter = ButtonDefaults.disabledContainerPainter(containerPainter),
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.buttonWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: @Composable RowScope.() -> Unit
): Unit
Wear Material3 Button that offers parameters for container image backgrounds, with three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.
An image background is a means to reinforce the meaning of information in a Button. Buttons should have a content color that contrasts with the background image and scrim.
This Button takes containerPainter for the container image background to be drawn when the button is enabled and disabledContainerPainter for the image background when the button is disabled (the ButtonColors containerColor and disabledContainerColor properties are ignored). It is recommended to use ButtonDefaults.containerPainter to create the painters so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The Button is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the Button height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.
Button can be enabled or disabled. A disabled button will not respond to click events.
Example of a Button with an image background, an icon and a secondary label:
import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text Button( onClick = { /* Do something */ }, containerPainter = ButtonDefaults.containerPainter( image = painterResource(id = R.drawable.backgroundimage) ), enabled = enabled, label = { Text("Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", ) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
containerPainter: Painter |
The |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
disabledContainerPainter: Painter = ButtonDefaults.disabledContainerPainter(containerPainter) |
|
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.buttonWithContainerPainterColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. |
ButtonGroup
@Composable
fun ButtonGroup(
modifier: Modifier = Modifier,
spacing: Dp = ButtonGroupDefaults.Spacing,
expansionWidth: Dp = ButtonGroupDefaults.ExpansionWidth,
contentPadding: PaddingValues = ButtonGroupDefaults.fullWidthPaddings(),
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
content: @Composable ButtonGroupScope.() -> Unit
): Unit
Layout component to implement an expressive group of buttons in a row, that react to touch by growing the touched button, (while the neighbor(s) shrink to accommodate and keep the group width constant).
Example of a ButtonGroup:
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonGroup import androidx.wear.compose.material3.Text val interactionSource1 = remember { MutableInteractionSource() } val interactionSource2 = remember { MutableInteractionSource() } Box(contentAlignment = Alignment.Center) { ButtonGroup(Modifier.fillMaxWidth()) { Button( onClick = {}, modifier = Modifier.animateWidth(interactionSource1), interactionSource = interactionSource1, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Text("L") } } Button( onClick = {}, modifier = Modifier.animateWidth(interactionSource2), interactionSource = interactionSource2, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Text("R") } } } }
Example of 3 buttons, the middle one bigger ButtonGroup:
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.LayoutDirection import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonGroup import androidx.wear.compose.material3.Text val interactionSource1 = remember { MutableInteractionSource() } val interactionSource2 = remember { MutableInteractionSource() } val interactionSource3 = remember { MutableInteractionSource() } var rtl by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { CompositionLocalProvider( LocalLayoutDirection provides if (rtl) LayoutDirection.Rtl else LayoutDirection.Ltr ) { ButtonGroup(Modifier.fillMaxWidth().align(Alignment.Center)) { Button( onClick = {}, modifier = Modifier.animateWidth(interactionSource1), interactionSource = interactionSource1, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Text("A") } } Button( onClick = {}, modifier = Modifier.weight(1.5f).animateWidth(interactionSource2), interactionSource = interactionSource2, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Text("B") } } Button( onClick = {}, modifier = Modifier.animateWidth(interactionSource3), interactionSource = interactionSource3, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Text("C") } } } } Button(modifier = Modifier.align(Alignment.BottomCenter), onClick = { rtl = !rtl }) { Text(if (rtl) "RTL" else "LTR") } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
Modifier to be applied to the button group |
spacing: Dp = ButtonGroupDefaults.Spacing |
the amount of spacing between buttons |
expansionWidth: Dp = ButtonGroupDefaults.ExpansionWidth |
how much buttons grow when pressed |
contentPadding: PaddingValues = ButtonGroupDefaults.fullWidthPaddings() |
The spacing values to apply internally between the container and the content |
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically |
the vertical alignment of the button group's children. |
content: @Composable ButtonGroupScope.() -> Unit |
the content and properties of each button. The Ux guidance is to use no more than 3 buttons within a ButtonGroup. Note that this content is on the |
Card
@Composable
fun Card(
modifier: Modifier = Modifier,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Base level Wear Material 3 Card that offers a single slot to take any content.
This Card does not handle input events - see the other Card overloads if you want a clickable Card.
Is used as the container for more opinionated Card components that take specific content such as icons, images, titles, subtitles and labels.
The Card is Rectangle-shaped with rounded corners by default.
Example of a non-clickable Card:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text Card { Text("Non Clickable Card") }
For more information, see the Cards Wear OS Material design guide.
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
Modifier to be applied to the card |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
Card
@Composable
fun Card(
containerPainter: Painter,
modifier: Modifier = Modifier,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Wear Material 3 Card that takes a container painter for drawing a background image, and offers a single slot to take any content.
This Card does not handle input events - see the other Card overloads if you want a clickable Card.
An image background is a means to reinforce the meaning of information in a Card. Cards should have a content color that contrasts with the background image and scrim. This Card takes containerPainter for the container image background to be drawn (the CardColors containerColor property is ignored). It is recommended to use CardDefaults.containerPainter to create the painter so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The Card is Rectangle-shaped with rounded corners by default.
Example of a non-clickable Card with an image background:
import androidx.compose.foundation.background import androidx.compose.ui.res.painterResource import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Text Card( containerPainter = CardDefaults.containerPainter(image = painterResource(id = R.drawable.backgroundimage)) ) { Text("Non clickable image card") }
| Parameters | |
|---|---|
containerPainter: Painter |
The |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardWithContainerPainterColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
Card
@Composable
fun Card(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Base level Wear Material 3 Card that offers a single slot to take any content.
Is used as the container for more opinionated Card components that take specific content such as icons, images, titles, subtitles and labels.
The Card is Rectangle-shaped with rounded corners by default.
Cards can be enabled or disabled. A disabled card will not respond to click events.
Example of a Card with onClick:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text Card(onClick = { /* Do something */ }) { Text("Card") }
Example of Card with onLongClick:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text Card( onClick = { /* Do something */ }, onLongClick = onLongClickHandler, onLongClickLabel = "Long click", ) { Text("Card with long click") }
Card does not constrain the height of its contents by default. Where necessary to do that, use Modifier.height(IntrinsicSize.Min) as shown in this example:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.height import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text Card( onClick = { /* Do something */ }, // Constrains the card to fill background up to the intrinsic height. modifier = Modifier.height(IntrinsicSize.Min), ) { Text("Card", modifier = Modifier.fillMaxHeight().background(Color.Red)) }
For more information, see the Cards Wear OS Material design guide.
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
Card
@Composable
fun Card(
onClick: () -> Unit,
containerPainter: Painter,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Wear Material 3 Card that takes a container painter for drawing a background image, and offers a single slot to take any content.
An image background is a means to reinforce the meaning of information in a Card. Cards should have a content color that contrasts with the background image and scrim. This Card takes containerPainter for the container image background to be drawn (the CardColors containerColor property is ignored). It is recommended to use CardDefaults.containerPainter to create the painter so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The Card is Rectangle-shaped with rounded corners by default.
Cards can be enabled or disabled. A disabled card will not respond to click events.
Example of a Card with an image background:
import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.ui.res.painterResource import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Text Card( onClick = { /* Do something */ }, containerPainter = CardDefaults.containerPainter(image = painterResource(id = R.drawable.backgroundimage)), ) { Text("Image card") }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
containerPainter: Painter |
The |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardWithContainerPainterColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
CheckboxButton
@Composable
fun CheckboxButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = CheckboxButtonDefaults.checkboxButtonShape,
colors: CheckboxButtonColors = CheckboxButtonDefaults.checkboxButtonColors(),
contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material CheckboxButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start and a column containing the two label slots in the middle.
The CheckboxButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the CheckboxButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
Samples: Example of a CheckboxButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.CheckboxButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text var checked by remember { mutableStateOf(true) } CheckboxButton( label = { Text("Checkbox Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, secondaryLabel = { Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis) }, checked = checked, onCheckedChange = { checked = it }, icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") }, enabled = true, )
CheckboxButton can be enabled or disabled. A disabled button will not respond to click events.
The recommended set of CheckboxButton colors can be obtained from CheckboxButtonDefaults, e.g. CheckboxButtonDefaults.checkboxButtonColors.
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this button's checked status is changed. |
modifier: Modifier = Modifier |
Modifier to be applied to the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = CheckboxButtonDefaults.checkboxButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: CheckboxButtonColors = CheckboxButtonDefaults.checkboxButtonColors() |
|
contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
icon: (@Composable BoxScope.() -> Unit)? = null |
An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be a horizontally and vertically center aligned icon of size 24.dp. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned and no more than 2 lines of text. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned and no more than 3 lines of text. |
ChildButton
@Composable
fun ChildButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.childButtonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
Base level Wear Material3 ChildButton that offers a single slot to take any content. Used as the container for more opinionated ChildButton components that take specific content such as icons and labels.
The ChildButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the ChildButton height adjusts to accommodate the contents. The ChildButton can have an icon or image horizontally parallel to the two lines of text.
ChildButton takes the ButtonDefaults.childButtonColors color scheme by default, with a transparent background and no border. This is a low-emphasis button for optional or supplementary actions with the least amount of prominence.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
ChildButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a ChildButton:
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.onClick import androidx.compose.ui.text.style.TextAlign import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ChildButton import androidx.wear.compose.material3.Text ChildButton( onClick = { /* Do something */ }, label = { Text("Child Button", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth()) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.childButtonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the ChildButton |
ChildButton
@Composable
fun ChildButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.childButtonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: @Composable RowScope.() -> Unit
): Unit
Wear Material3 ChildButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.
The ChildButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the ChildButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.
If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.
ChildButton takes the ButtonDefaults.childButtonColors color scheme by default, with a transparent background and no border. This is a low-emphasis button for optional or supplementary actions with the least amount of prominence.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
ChildButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a ChildButton with an icon and secondary label:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.ChildButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text ChildButton( onClick = { /* Do something */ }, label = { Text("Child Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.childButtonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. |
CircularProgressIndicator
@Composable
fun CircularProgressIndicator(
modifier: Modifier = Modifier,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = CircularProgressIndicatorDefaults.IndeterminateStrokeWidth,
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit
Indeterminate Material Design circular progress indicator.
Indeterminate progress indicator expresses an unspecified wait time and spins indefinitely.
Example of indeterminate circular progress indicator:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.CircularProgressIndicator Box(modifier = Modifier.fillMaxSize()) { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
Modifier to be applied to the CircularProgressIndicator. |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = CircularProgressIndicatorDefaults.IndeterminateStrokeWidth |
The stroke width for the progress indicator. The recommended values is |
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance. |
CircularProgressIndicator
@Composable
fun CircularProgressIndicator(
progress: () -> Float,
modifier: Modifier = Modifier,
enabled: Boolean = true,
allowProgressOverflow: Boolean = false,
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
endAngle: Float = startAngle,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit
Material Design circular progress indicator. Progress changes are animated.
Example of a full screen CircularProgressIndicator. Note that the padding CircularProgressIndicatorDefaults.FullScreenPadding should be applied:
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.ui.Modifier import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ProgressIndicatorDefaults Box( modifier = Modifier.background(MaterialTheme.colorScheme.background) .padding(CircularProgressIndicatorDefaults.FullScreenPadding) .fillMaxSize() ) { CircularProgressIndicator(progress = { 0.25f }, startAngle = 120f, endAngle = 60f) }
Example of progress showing overflow value (more than 1) by CircularProgressIndicator:
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.ui.Modifier import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ProgressIndicatorDefaults Box( modifier = Modifier.background(MaterialTheme.colorScheme.background) .padding(CircularProgressIndicatorDefaults.FullScreenPadding) .fillMaxSize() ) { CircularProgressIndicator( // Overflow value of 120% progress = { 1.2f }, allowProgressOverflow = true, startAngle = 120f, endAngle = 60f, ) }
Example of progress indicator wrapping media control by CircularProgressIndicator:
import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton import androidx.wear.compose.material3.IconButtonDefaults import androidx.wear.compose.material3.MaterialTheme var isPlaying by remember { mutableStateOf(false) } val buttonPadding = 4.dp val progressStrokeWidth = 4.dp val progress = 0.75f Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) { // The CircularProgressIndicator should be around the IconButton, with an extra gap between // then of 'buttonPadding'. We multiply by 2 because the size includes progressStrokeWidth // at top and bottom and the buttonPadding at top and bottom. CircularProgressIndicator( modifier = Modifier.align(Alignment.Center) .size( IconButtonDefaults.DefaultButtonSize + progressStrokeWidth * 2 + buttonPadding * 2 ), progress = { progress }, strokeWidth = progressStrokeWidth, ) IconButton( modifier = Modifier.align(Alignment.Center) .semantics { // Set custom progress semantics for accessibility. contentDescription = String.format( "Play/pause button, track progress: %.0f%%", progress * 100, ) } .clip(CircleShape) .background(MaterialTheme.colorScheme.surfaceContainerLow), onClick = { isPlaying = !isPlaying }, ) { Icon( imageVector = if (isPlaying) Icons.Filled.Close else Icons.Filled.PlayArrow, contentDescription = null, ) } }
Example of a CircularProgressIndicator with small progress values:
import androidx.compose.foundation.layout.Box 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.unit.dp import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.ProgressIndicatorDefaults Box { CircularProgressIndicator( // Small progress values like 2% will be rounded up to at least the stroke width. progress = { 0.02f }, modifier = Modifier.fillMaxSize().padding(CircularProgressIndicatorDefaults.FullScreenPadding), startAngle = 120f, endAngle = 60f, strokeWidth = 10.dp, colors = ProgressIndicatorDefaults.colors( indicatorColor = Color.Green, trackColor = Color.White, ), ) }
Progress indicators express the proportion of completion of an ongoing task.
| Parameters | |
|---|---|
progress: () -> Float |
The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Progress changes will be animated. |
modifier: Modifier = Modifier |
Modifier to be applied to the CircularProgressIndicator. |
enabled: Boolean = true |
controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is |
allowProgressOverflow: Boolean = false |
When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color |
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle |
The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees |
endAngle: Float = startAngle |
The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth |
The stroke width for the progress indicator. The recommended values are |
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance. |
CompactButton
@Composable
fun CompactButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.compactButtonShape,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.CompactButtonContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: (@Composable RowScope.() -> Unit)? = null
): Unit
A Wear Material3 CompactButton that offers two slots and a specific layout for an icon and label. Both the icon and label are optional however it is expected that at least one will be provided.
The CompactButton is Stadium shaped and has a max height designed to take no more than one line of text and/or one icon. The default max height is ButtonDefaults.CompactButtonHeight. This includes a visible button height of 32.dp and 8.dp of padding above and below the button in order to meet accessibility guidelines that request a minimum of 48.dp height and width of tappable area.
If an icon is provided then the labels should be "start" aligned, e.g. left aligned in left-to-right mode so that the text starts next to the icon.
The items are laid out as follows.
-
If a label is provided then the button will be laid out with the optional icon at the start of a row followed by the label with a default max height of
ButtonDefaults.CompactButtonHeight. -
If only an icon is provided it will be laid out vertically and horizontally centered with a default height of
ButtonDefaults.CompactButtonHeightand the default width ofButtonDefaults.IconOnlyCompactButtonWidth
If neither icon nor label is provided then the button will displayed like an icon only button but with no contents or background color.
CompactButton takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.
Other recommended ButtonColors for different levels of emphasis are: ButtonDefaults.filledTonalButtonColors, ButtonDefaults.outlinedButtonColors and ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.buttonWithContainerPainterColors.
CompactButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a CompactButton with an icon and a label
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.CompactButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text CompactButton( onClick = { /* Do something */ }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize), ) }, modifier = modifier, ) { Text("Compact Button", maxLines = 1, overflow = TextOverflow.Ellipsis) }
Example of a CompactButton with an icon and label and with ButtonDefaults.filledTonalButtonColors
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.CompactButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text CompactButton( onClick = { /* Do something */ }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize), ) }, colors = ButtonDefaults.filledTonalButtonColors(), modifier = modifier, ) { Text("Filled Tonal Compact Button", maxLines = 1, overflow = TextOverflow.Ellipsis) }
Example of a CompactButton with an icon and label and with ButtonDefaults.outlinedButtonBorder and ButtonDefaults.outlinedButtonColors. The example includes a Text that expands and collapses when the CompactButton is clicked.
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowUp import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.onClick import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.CompactButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text Column(horizontalAlignment = Alignment.CenterHorizontally) { var expanded by remember { mutableStateOf(false) } if (expanded) { Text("A multiline string showing two lines") } else { Text("One line text") } Spacer(Modifier.height(ButtonDefaults.IconSpacing)) CompactButton( onClick = { expanded = !expanded }, colors = ButtonDefaults.outlinedButtonColors(), border = ButtonDefaults.outlinedButtonBorder(enabled = true), modifier = modifier, ) { if (expanded) { Text("Show Less", maxLines = 1, overflow = TextOverflow.Ellipsis) } else { Text("Show More", maxLines = 1, overflow = TextOverflow.Ellipsis) } Spacer(Modifier.width(ButtonDefaults.IconSpacing)) if (expanded) { Icon( Icons.Filled.KeyboardArrowUp, contentDescription = "Collapse", modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize), ) } else { Icon( Icons.Filled.KeyboardArrowDown, contentDescription = "Expand", modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize), ) } } }
Example of a CompactButton with onLongClick:
import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.CompactButton import androidx.wear.compose.material3.Text CompactButton( onClick = onClickHandler, onLongClick = onLongClickHandler, onLongClickLabel = "Long click", label = { Text("Long clickable") }, modifier = modifier.semantics { // Also override the 'click label' to say 'Double tap to press' instead of // the usual 'Double tap to activate'. onClick("press") { false } }, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.compactButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.buttonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.CompactButtonContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's main label. The contents are expected to be a single line of text which is "start" aligned if there is an icon preset and "center" aligned if not. |
ConfirmationDialog
@Composable
fun ConfirmationDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors(),
properties: DialogProperties = DialogProperties(),
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis,
content: @Composable () -> Unit
): Unit
Shows a transient ConfirmationDialog with an icon and optional very short curvedText. The length of the curved text should be very short and should not exceed 1-2 words. If a longer text is required, then the alternative ConfirmationDialog overload with slot for linear text should be used instead.
The ConfirmationDialog shows a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation dialog, the visible parameter should be set to false.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of ConfirmationDialog.
Example of a ConfirmationDialog with an icon and a curved text content:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText import androidx.wear.compose.material3.samples.icons.FavoriteIcon var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } // Has an icon and a short curved text content, which will be displayed along the bottom edge of // the screen. val curvedTextStyle = ConfirmationDialogDefaults.curvedTextStyle ConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText("Confirmed", curvedTextStyle) }, ) { FavoriteIcon(ConfirmationDialogDefaults.IconSize) }
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the confirmation dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed - either by swiping right or when the |
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors() |
A |
properties: DialogProperties = DialogProperties() |
An optional |
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis |
The duration in milliseconds for which the dialog is displayed. This value will be adjusted by the accessibility manager according to the content displayed. |
content: @Composable () -> Unit |
A slot for displaying an icon inside the confirmation dialog. It's recommended to set its size to |
ConfirmationDialog
@Composable
fun ConfirmationDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
text: (@Composable ColumnScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors(),
properties: DialogProperties = DialogProperties(),
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis,
content: @Composable () -> Unit
): Unit
Shows a transient ConfirmationDialog with an icon and optional short text. The length of the text should not exceed 3 lines. If the text is very short and fits into 1-2 words, consider using the alternative ConfirmationDialog overload with the curvedText parameter instead.
The confirmation dialog will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation dialog, visible parameter should be set to false.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of ConfirmationDialog.
Example of a ConfirmationDialog with an icon and a text which fits into 3 lines:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } // Has an icon and a text content. Text will be displayed in the center of the screen below the // icon. ConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, text = { Text(text = "Your message has been sent") }, ) { Icon( imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = null, modifier = Modifier.size(ConfirmationDialogDefaults.SmallIconSize), ) }
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the confirmation dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed - either by swiping right or when the |
text: (@Composable ColumnScope.() -> Unit)? |
A slot for displaying text below the icon. It should not exceed 3 lines. |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors() |
A |
properties: DialogProperties = DialogProperties() |
An optional |
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis |
The duration in milliseconds for which the dialog is displayed. This value will be adjusted by the accessibility manager according to the content displayed. |
content: @Composable () -> Unit |
A slot for displaying an icon inside the confirmation dialog, which can be animated. It's recommended to set its size to |
ConfirmationDialogContent
@Composable
fun ConfirmationDialogContent(
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors(),
content: @Composable () -> Unit
): Unit
This overload of ConfirmationDialogContent provides the content for a ConfirmationDialog with an icon and optional very short curvedText. The length of the curved text should be very short and should not exceed 1-2 words. If a longer text is required, then the alternative ConfirmationDialog overload with slot for linear text should be used instead.
Prefer using ConfirmationDialog directly, which provides built-in animations when showing/hiding the dialog. This composable may be used to provide the content for a confirmation dialog if custom show/hide animations are required.
Example of a ConfirmationDialog with an icon and a curved text content:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText import androidx.wear.compose.material3.samples.icons.FavoriteIcon var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } // Has an icon and a short curved text content, which will be displayed along the bottom edge of // the screen. val curvedTextStyle = ConfirmationDialogDefaults.curvedTextStyle ConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText("Confirmed", curvedTextStyle) }, ) { FavoriteIcon(ConfirmationDialogDefaults.IconSize) }
| Parameters | |
|---|---|
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors() |
A |
content: @Composable () -> Unit |
A slot for displaying an icon inside the confirmation dialog. It's recommended to set its size to |
ConfirmationDialogContent
@Composable
fun ConfirmationDialogContent(
text: (@Composable ColumnScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors(),
content: @Composable () -> Unit
): Unit
This overload of ConfirmationDialogContent provides the content for a ConfirmationDialog with with an icon and optional short text. The length of the text should not exceed 3 lines. If the text is very short and fits into 1-2 words, consider using the alternative ConfirmationDialog overload with the curvedText parameter instead.
Prefer using ConfirmationDialog directly, which provides built-in animations when showing/hiding the dialog. This composable may be used to provide the content for a confirmation dialog if custom show/hide animations are required.
Example of a ConfirmationDialog with an icon and a text which fits into 3 lines:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } // Has an icon and a text content. Text will be displayed in the center of the screen below the // icon. ConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, text = { Text(text = "Your message has been sent") }, ) { Icon( imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = null, modifier = Modifier.size(ConfirmationDialogDefaults.SmallIconSize), ) }
| Parameters | |
|---|---|
text: (@Composable ColumnScope.() -> Unit)? |
A slot for displaying text below the icon. It should not exceed 3 lines. |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.colors() |
A |
content: @Composable () -> Unit |
A slot for displaying an icon inside the confirmation dialog. It's recommended to set its size to |
DatePicker
@RequiresApi(value = 26)
@Composable
fun DatePicker(
initialDate: LocalDate,
onDatePicked: (LocalDate) -> Unit,
modifier: Modifier = Modifier,
minValidDate: LocalDate? = null,
maxValidDate: LocalDate? = null,
datePickerType: DatePickerType = DatePickerDefaults.datePickerType,
colors: DatePickerColors = DatePickerDefaults.datePickerColors()
): Unit
Full screen DatePicker with day, month, year.
This component is designed to take most/all of the screen and utilizes large fonts.
Example of a DatePicker:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.DatePicker import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text var showDatePicker by remember { mutableStateOf(true) } var datePickerDate by remember { mutableStateOf(LocalDate.now()) } val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) .withLocale(LocalConfiguration.current.locales[0]) if (showDatePicker) { DatePicker( initialDate = datePickerDate, // Initialize with last picked date on reopen onDatePicked = { datePickerDate = it showDatePicker = false }, ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( onClick = { showDatePicker = true }, label = { Text("Selected Date") }, secondaryLabel = { Text(datePickerDate.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
Example of a DatePicker shows the picker options in year-month-day order:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.DatePicker import androidx.wear.compose.material3.DatePickerType import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text var showDatePicker by remember { mutableStateOf(true) } var datePickerDate by remember { mutableStateOf(LocalDate.now()) } val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) .withLocale(LocalConfiguration.current.locales[0]) if (showDatePicker) { DatePicker( initialDate = datePickerDate, // Initialize with last picked date on reopen onDatePicked = { datePickerDate = it showDatePicker = false }, datePickerType = DatePickerType.YearMonthDay, ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( onClick = { showDatePicker = true }, label = { Text("Selected Date") }, secondaryLabel = { Text(datePickerDate.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
Example of a DatePicker with a minValidDate:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.DatePicker import androidx.wear.compose.material3.DatePickerType import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text val currentDate = LocalDate.now() var showDatePicker by remember { mutableStateOf(true) } var datePickerDate by remember { mutableStateOf(LocalDate.now()) } val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) .withLocale(LocalConfiguration.current.locales[0]) if (showDatePicker) { DatePicker( initialDate = datePickerDate, // Initialize with last picked date on reopen onDatePicked = { datePickerDate = it showDatePicker = false }, datePickerType = DatePickerType.YearMonthDay, minValidDate = currentDate, ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( onClick = { showDatePicker = true }, label = { Text("Selected Date") }, secondaryLabel = { Text(datePickerDate.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
| Parameters | |
|---|---|
initialDate: LocalDate |
The initial value to be displayed in the DatePicker. |
onDatePicked: (LocalDate) -> Unit |
The callback that is called when the user confirms the date selection. It provides the selected date as |
modifier: Modifier = Modifier |
Modifier to be applied to the |
minValidDate: LocalDate? = null |
Optional minimum date that can be selected in the DatePicker (inclusive). |
maxValidDate: LocalDate? = null |
Optional maximum date that can be selected in the DatePicker (inclusive). |
datePickerType: DatePickerType = DatePickerDefaults.datePickerType |
The different |
colors: DatePickerColors = DatePickerDefaults.datePickerColors() |
|
Dialog
@Composable
fun Dialog(
visible: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
properties: DialogProperties = DialogProperties(),
content: @Composable () -> Unit
): Unit
A base dialog component used by AlertDialog and ConfirmationDialog variations. This dialog provides a full-screen experience with custom entry/exit animations.
Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task.
The caller should consider whether timeText or scrollIndicator are needed on this dialog, in this case they should provide that in their content by using ScreenScaffold (with suitable scrollState if that's required).
| Parameters | |
|---|---|
visible: Boolean |
A boolean value that determines whether the dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed by swiping right. Implementation of this lambda must remove the dialog from the composition hierarchy e.g. by setting |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
properties: DialogProperties = DialogProperties() |
An optional |
content: @Composable () -> Unit |
A composable function that defines the content of the dialog. |
EdgeButton
@Composable
fun EdgeButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
buttonSize: EdgeButtonSize = EdgeButtonSize.Small,
enabled: Boolean = true,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
content: @Composable RowScope.() -> Unit
): Unit
Wear Material3 EdgeButton that offers a single slot to take any content.
The EdgeButton has a special shape designed for the bottom of the screen, as it almost follows the screen's curvature, so it should be allowed to take the full width and touch the bottom of the screen. It has 4 standard sizes, taking 1 line of text for the extra small, 2 for small and medium, and 3 for the large. See the standard values on ButtonDefaults, and specify it using the buttonSize parameter. Optionally, a single icon can be used instead of the text.
This button represents the most important action on the screen, and must take the whole width of the screen as well as being anchored to the screen bottom.
EdgeButton takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen. Other possible colors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors and OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors
EdgeButton is not intended to be used with an image background.
Edge button can be enabled or disabled. A disabled button will not respond to click events.
Example of an EdgeButton:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column 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.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.EdgeButtonSize import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButton import androidx.wear.compose.material3.TextButtonDefaults val sizes = listOf( EdgeButtonSize.ExtraSmall, EdgeButtonSize.Small, EdgeButtonSize.Medium, EdgeButtonSize.Large, ) val sizeNames = listOf("XS", "S", "M", "L") var size by remember { mutableIntStateOf(0) } Box(Modifier.fillMaxSize()) { Column( Modifier.align(Alignment.TopCenter).fillMaxSize().padding(top = 0.dp), verticalArrangement = Arrangement.spacedBy(0.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { Column(modifier = Modifier.weight(1f)) { Row { Spacer(modifier = Modifier.height(16.dp)) } Row { Text("Sizes", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center) } Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, ) { repeat(sizeNames.size) { TextButton( onClick = { size = it }, modifier = Modifier.size(TextButtonDefaults.SmallButtonSize), ) { Text(sizeNames[it]) } } } } EdgeButton(onClick = { /* Do something */ }, buttonSize = sizes[size]) { Icon( Icons.Filled.Check, contentDescription = "Check icon", modifier = Modifier.size(ButtonDefaults.IconSize), ) } } }
For a sample integrating with ScalingLazyColumn, see:
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.EdgeButtonSize import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RadioButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.CheckIcon val state = rememberScalingLazyListState() val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f val verticalPadding = LocalConfiguration.current.screenHeightDp.dp * 0.16f val colors = listOf( "Filled" to ButtonDefaults.buttonColors(), "Filled Variant" to ButtonDefaults.filledVariantButtonColors(), "Filled Tonal" to ButtonDefaults.filledTonalButtonColors(), "Outlined" to ButtonDefaults.outlinedButtonColors(), "Disabled" to ButtonDefaults.buttonColors(), ) var selectedColor by remember { mutableIntStateOf(0) } val types = listOf("Icon only" to 0, "Text only" to 1) var selectedType by remember { mutableIntStateOf(0) } ScreenScaffold( scrollState = state, contentPadding = PaddingValues(horizontal = horizontalPadding, vertical = verticalPadding), edgeButton = { EdgeButton( modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // An overscroll effect should be applied to the EdgeButton for proper // scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), onClick = {}, buttonSize = EdgeButtonSize.Medium, colors = colors[selectedColor].second, border = if (colors[selectedColor].first == "Outlined") ButtonDefaults.outlinedButtonBorder(true) else null, enabled = colors[selectedColor].first != "Disabled", ) { if (selectedType == 0) { // Remove extra spacing around the icon so it integrates better into the scroll. CheckIcon(Modifier.size(21.dp).wrapContentSize(unbounded = true).size(32.dp)) } else { Text("Ok") } } }, ) { contentPadding -> ScalingLazyColumn( state = state, modifier = Modifier.fillMaxSize().selectableGroup(), autoCentering = null, contentPadding = contentPadding, horizontalAlignment = Alignment.CenterHorizontally, ) { item { Text("Color") } items(colors.size) { ix -> RadioButton( label = { Text(colors[ix].first) }, selected = selectedColor == ix, onSelect = { selectedColor = ix }, modifier = Modifier.fillMaxWidth(), ) } item { Text("Type") } items(types.size) { ix -> RadioButton( label = { Text(types[ix].first) }, selected = selectedType == ix, onSelect = { selectedType = ix }, modifier = Modifier.fillMaxWidth(), ) } } }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button. When animating the button to appear/ disappear from the screen, a Modifier.height can be used to change the height of the component, but that won't change the space available for the content (though it may be scaled) |
buttonSize: EdgeButtonSize = EdgeButtonSize.Small |
Defines the size of the button. See |
enabled: Boolean = true |
Controls the enabled state of the button. When |
colors: ButtonColors = ButtonDefaults.buttonColors() |
|
border: BorderStroke? = null |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the Button. Either an Icon or Text. Note that when using an Icon is recommended to remove any extra spacing the icon may have, either processing the image or using something like the list sample. |
FadingExpandingLabel
@Composable
fun FadingExpandingLabel(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign,
lineHeight: TextUnit = TextUnit.Unspecified,
softWrap: Boolean = true,
maxLines: Int = LocalTextConfiguration.current.maxLines,
minLines: Int = 1,
textStyle: TextStyle = LocalTextStyle.current,
animationSpec: FiniteAnimationSpec<Float> = FadingExpandingLabelDefaults.animationSpec
): Unit
Animates label text for which the number of lines can vary, changing the size of the container component.
Displays the given string in a Text, with an animation that fades text in line by line when new lines of text are added or removed. This is intended to be be used for labels in a Button or Card, where we want the container to expand to fit the contents when the lines of the text change.
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth 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.text.style.TextAlign import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.FadingExpandingLabel var text by remember { mutableStateOf("Text Text Text Text") } var lines by remember { mutableIntStateOf(1) } Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( onClick = { lines = lines % 3 + 1 text = (1..lines).joinToString(separator = " ") { "Text Text Text Text" } }, modifier = Modifier.fillMaxWidth(), label = { FadingExpandingLabel(text = text, textAlign = TextAlign.Left) }, ) }
| Parameters | |
|---|---|
text: String |
Text string that will be shown. |
modifier: Modifier = Modifier |
Modifier to be applied to the animated text. |
color: Color = Color.Unspecified |
|
fontSize: TextUnit = TextUnit.Unspecified |
The size of glyphs to use when painting the text. See |
fontStyle: FontStyle? = null |
The typeface variant to use when drawing the letters (e.g., italic). See |
fontWeight: FontWeight? = null |
The typeface thickness to use when painting the text (e.g., |
fontFamily: FontFamily? = null |
The font family to be used when rendering the text. See |
letterSpacing: TextUnit = TextUnit.Unspecified |
The amount of space to add between each letter. See |
textDecoration: TextDecoration? = null |
The decorations to paint on the text (e.g., an underline). See |
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign |
The alignment of the text within the lines of the paragraph. See |
lineHeight: TextUnit = TextUnit.Unspecified |
Line height for the Paragraph in |
softWrap: Boolean = true |
Whether the text should break at soft line breaks. If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. If |
maxLines: Int = LocalTextConfiguration.current.maxLines |
An optional maximum number of lines for the text to span, wrapping if necessary. If it is not null, then it must be greater than zero. |
minLines: Int = 1 |
The minimum height in terms of minimum number of visible lines. It is required that 1 <= |
textStyle: TextStyle = LocalTextStyle.current |
|
animationSpec: FiniteAnimationSpec<Float> = FadingExpandingLabelDefaults.animationSpec |
Animation spec for the text fade animation. |
FailureConfirmationDialog
@Composable
fun FailureConfirmationDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.failureColors(),
properties: DialogProperties = DialogProperties(),
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis,
content: @Composable () -> Unit = { ConfirmationDialogDefaults.ConnectionFailureIcon() }
): Unit
Shows a FailureConfirmationDialog with a failure icon and an optional short curved text. This variation of confirmation dialog indicates an unsuccessful operation or action.
The confirmation dialog will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, visible parameter should be set to false.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of FailureConfirmationDialog.
Example of FailureConfirmationDialog usage with default icon:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FailureConfirmationDialog import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } val text = "Failure" val style = ConfirmationDialogDefaults.curvedTextStyle FailureConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText(text, style) }, )
Example of FailureConfirmationDialog with the variant failure icon for a generic error.
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FailureConfirmationDialog import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } val text = "Failure" val style = ConfirmationDialogDefaults.curvedTextStyle FailureConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText(text, style) }, content = { ConfirmationDialogDefaults.GenericFailureIcon() }, )
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the confirmation dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed - either by swiping right or when the |
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.failureColors() |
A |
properties: DialogProperties = DialogProperties() |
An optional |
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis |
The duration in milliseconds for which the dialog is displayed. This value will be adjusted by the accessibility manager according to the content displayed. |
content: @Composable () -> Unit = { ConfirmationDialogDefaults.ConnectionFailureIcon() } |
A slot for displaying an icon inside the confirmation dialog, which can be animated. The default value is |
FailureConfirmationDialogContent
@Composable
fun FailureConfirmationDialogContent(
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.failureColors(),
content: @Composable () -> Unit = { ConfirmationDialogDefaults.ConnectionFailureIcon() }
): Unit
FailureConfirmationDialogContent provides the content for a failure confirmation dialog with icon and an optional short curved text. This variation of confirmation dialog indicates an unsuccessful operation or action.
Prefer using FailureConfirmationDialog directly, which provides built-in animations when showing/hiding the dialog. This composable may be used to provide the content for a confirmation dialog if custom show/hide animations are required.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of FailureConfirmationDialog.
| Parameters | |
|---|---|
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.failureColors() |
A |
content: @Composable () -> Unit = { ConfirmationDialogDefaults.ConnectionFailureIcon() } |
A slot for displaying an icon inside the confirmation dialog, which can be animated. The default value is |
FilledIconButton
@Composable
fun FilledIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shapes: IconButtonShapes = IconButtonDefaults.shapes(),
colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors(),
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material FilledIconButton is a circular, icon-only button with a colored background and a contrasting content color. It offers a single slot to take an icon or image.
Set the size of the FilledIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.
The recommended IconButton sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.
Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButton size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeIconSize directly.
FilledIconButton can be enabled or disabled. A disabled button will not respond to click events.
Example of FilledIconButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.FilledIconButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton FilledIconButton(onClick = { /* Do something */ }) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shapes: IconButtonShapes = IconButtonDefaults.shapes() |
Defines the shape for this button. Defaults to a static shape based on |
colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors() |
|
border: BorderStroke? = null |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable BoxScope.() -> Unit |
The content displayed on the icon button, expected to be icon or image. |
FilledTonalButton
@Composable
fun FilledTonalButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
Base level Wear Material3 FilledTonalButton that offers a single slot to take any content. Used as the container for more opinionated FilledTonalButton components that take specific content such as icons and labels.
The FilledTonalButton is Stadium-shaped by default and has a max height designed to take no more than two lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the FilledTonalButton height adjusts to accommodate the contents. The FilledTonalButton can have an icon or image horizontally parallel to the two lines of text.
FilledTonalButton takes the ButtonDefaults.filledTonalButtonColors color scheme by default, with muted background, contrasting content color and no border. This is a medium-emphasis button for important actions that don't distract from other onscreen elements, such as final or unblocking actions in a flow with less emphasis than Button.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
FilledTonalButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a FilledTonalButton:
import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Text FilledTonalButton( onClick = { /* Do something */ }, label = { Text("Filled Tonal Button") }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the Button |
FilledTonalButton
@Composable
fun FilledTonalButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: @Composable RowScope.() -> Unit
): Unit
Wear Material3 FilledTonalButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.
The FilledTonalButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the FilledTonalButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.
If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.
If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.
FilledTonalButton takes the ButtonDefaults.filledTonalButtonColors color scheme by default, with muted background, contrasting content color and no border. This is a medium-emphasis button for important actions that don't distract from other onscreen elements, such as final or unblocking actions in a flow with less emphasis than Button.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
FilledTonalButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a FilledTonalButton with an icon and secondary label:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text FilledTonalButton( onClick = { /* Do something */ }, label = { Text("Filled Tonal Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors() |
|
border: BorderStroke? = null |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. |
FilledTonalIconButton
@Composable
fun FilledTonalIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shapes: IconButtonShapes = IconButtonDefaults.shapes(),
colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material FilledTonalIconButton is a circular, icon-only button with a muted, colored background and a contrasting icon color. It offers a single slot to take an icon or image.
Set the size of the FilledTonalIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.
The recommended icon button sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.
Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.
FilledTonalIconButton can be enabled or disabled. A disabled button will not respond to click events.
Example of FilledTonalIconButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.FilledTonalIconButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton FilledTonalIconButton(onClick = { /* Do something */ }) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shapes: IconButtonShapes = IconButtonDefaults.shapes() |
Defines the shape for this button. Defaults to a static shape based on |
colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors() |
|
border: BorderStroke? = null |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable BoxScope.() -> Unit |
The content displayed on the icon button, expected to be icon or image. |
HorizontalPageIndicator
@Composable
fun HorizontalPageIndicator(
pagerState: PagerState,
modifier: Modifier = Modifier,
selectedColor: Color = PageIndicatorDefaults.selectedColor,
unselectedColor: Color = PageIndicatorDefaults.unselectedColor,
backgroundColor: Color = PageIndicatorDefaults.backgroundColor
): Unit
Horizontal page indicator for use with HorizontalPager, representing the currently active page and the approximate number of pages. Pages are indicated as a Circle shape. The indicator shows up to six pages individually - if there are more than six pages, HorizontalPageIndicator shows a smaller indicator to the left and/or right to indicate that more pages are available.
Here's how different positions 0..10 might be visually represented: "X" is selected item, "O" and "o" full and half size items respectively.
O X O O O o - 2nd position out of 10. There are no more items on the left but more on the right.
o O O O X o - current page could be 6, 7 or 8 out of 10, as there are more potential pages on the left and on the right.
o O O O X O - current page is 9 out of 10, as there no more items on the right
To comply with Wear Material Design guidelines, this composable should be aligned to the bottom center of the screen using Alignment.BottomCenter, such as by setting modifier = Modifier.align(Alignment.BottomCenter). If HorizontalPageIndicator is used through HorizontalPagerScaffold, then alignment is implicitly set by HorizontalPagerScaffold.
Example usage with HorizontalPager:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.pager.HorizontalPager import androidx.wear.compose.foundation.pager.rememberPagerState import androidx.wear.compose.material3.AnimatedPage import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.HorizontalPageIndicator import androidx.wear.compose.material3.HorizontalPagerScaffold import androidx.wear.compose.material3.PagerScaffoldDefaults import androidx.wear.compose.material3.Text val pageCount = 9 val pagerState = rememberPagerState { pageCount } Box { HorizontalPagerScaffold( pagerState = pagerState, pageIndicator = { HorizontalPageIndicator(pagerState = pagerState) }, ) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior(state = pagerState), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe left and right") if (page == 0) { Spacer(modifier = Modifier.height(8.dp)) Button(onClick = navigateBack) { Text("Exit") } } } } } } }
| Parameters | |
|---|---|
pagerState: PagerState |
State of the |
modifier: Modifier = Modifier |
Modifier to be applied to the |
selectedColor: Color = PageIndicatorDefaults.selectedColor |
The color which will be used for a selected indicator item. |
unselectedColor: Color = PageIndicatorDefaults.unselectedColor |
The color which will be used for an unselected indicator item. |
backgroundColor: Color = PageIndicatorDefaults.backgroundColor |
The color which will be used for an indicator background. |
HorizontalPagerScaffold
@Composable
fun HorizontalPagerScaffold(
pagerState: PagerState,
modifier: Modifier = Modifier,
pageIndicator: (@Composable BoxScope.() -> Unit)? = { HorizontalPageIndicator(pagerState) },
pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
content: @Composable () -> Unit
): Unit
HorizontalPagerScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and HorizontalPagerScaffold lay out the structure of a Pager and coordinate transitions of the HorizontalPageIndicator and TimeText components.
HorizontalPagerScaffold displays the HorizontalPageIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and HorizontalPageIndicator according to whether the Pager is being paged, this is determined by the PagerState.
Example of using AppScaffold and HorizontalPagerScaffold:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.pager.HorizontalPager import androidx.wear.compose.foundation.pager.rememberPagerState import androidx.wear.compose.material3.AnimatedPage import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.HorizontalPagerScaffold import androidx.wear.compose.material3.PagerScaffoldDefaults import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior(state = pagerState), rotaryScrollableBehavior = null, ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe left and right") if (page == 0) { Spacer(modifier = Modifier.height(16.dp)) Button(onClick = navigateBack) { Text("Exit") } } } } } } } }
| Parameters | |
|---|---|
pagerState: PagerState |
The state of the pager controlling the page content. |
modifier: Modifier = Modifier |
The modifier to be applied to the scaffold. |
pageIndicator: (@Composable BoxScope.() -> Unit)? = { HorizontalPageIndicator(pagerState) } |
A composable function that defines the page indicator to be displayed. By default, it uses a |
pageIndicatorAnimationSpec: AnimationSpec<Float>? = null |
|
content: @Composable () -> Unit |
A composable function where a HorizontalPager can be added. |
Icon
@Composable
fun Icon(
bitmap: ImageBitmap,
contentDescription: String?,
modifier: Modifier = Modifier,
tint: Color = LocalContentColor.current
): Unit
Icon component that draws bitmap using tint, defaulting to LocalContentColor. For a clickable icon, see Button.
| Parameters | |
|---|---|
bitmap: ImageBitmap |
|
contentDescription: String? |
Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar |
modifier: Modifier = Modifier |
Optional |
tint: Color = LocalContentColor.current |
Tint to be applied to |
Icon
@Composable
fun Icon(
imageVector: ImageVector,
contentDescription: String?,
modifier: Modifier = Modifier,
tint: Color = LocalContentColor.current
): Unit
Icon component that draws imageVector using tint, defaulting to LocalContentColor. For a clickable icon, see IconButton.
| Parameters | |
|---|---|
imageVector: ImageVector |
|
contentDescription: String? |
Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar |
modifier: Modifier = Modifier |
Optional |
tint: Color = LocalContentColor.current |
Tint to be applied to |
Icon
@Composable
fun Icon(
painter: Painter,
contentDescription: String?,
modifier: Modifier = Modifier,
tint: Color = LocalContentColor.current
): Unit
Icon component that draws a painter using tint, defaulting to LocalContentColor. For a clickable icon, see Button.
| Parameters | |
|---|---|
painter: Painter |
|
contentDescription: String? |
Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar |
modifier: Modifier = Modifier |
Optional |
tint: Color = LocalContentColor.current |
Tint to be applied to |
IconButton
@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shapes: IconButtonShapes = IconButtonDefaults.shapes(),
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material IconButton is a circular, icon-only button with transparent background and no border. It offers a single slot to take icon or image content.
Set the size of the IconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.
The recommended IconButton sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.
Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.
IconButton can be enabled or disabled. A disabled button will not respond to click events.
Example of an IconButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton IconButton(onClick = { /* Do something */ }) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
Example of an IconButton with onLongClick:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton IconButton( onClick = { /* Do something for onClick*/ }, onLongClick = onLongClick, onLongClickLabel = "Long click", ) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
Example of an IconButton with shape animation of rounded corners on press:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.FilledIconButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton import androidx.wear.compose.material3.IconButtonDefaults FilledIconButton( onClick = { /* Do something */ }, shapes = IconButtonDefaults.animatedShapes(), colors = colors, ) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
Example of an IconButton with image content:
import androidx.compose.foundation.Image import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.layout.ContentScale import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton import androidx.wear.compose.material3.IconButtonDefaults IconButton(onClick = { /* Do something */ }, shapes = shapes, enabled = enabled) { Image( painter = painter, contentDescription = null, contentScale = ContentScale.Crop, modifier = if (enabled) Modifier else Modifier.alpha(IconButtonDefaults.DisabledImageOpacity), ) }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shapes: IconButtonShapes = IconButtonDefaults.shapes() |
Defines the shape for this button. Defaults to a static shape based on |
colors: IconButtonColors = IconButtonDefaults.iconButtonColors() |
|
border: BorderStroke? = null |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable BoxScope.() -> Unit |
The content displayed on the icon button, expected to be icon or image. |
IconToggleButton
@Composable
fun IconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconToggleButtonColors = IconToggleButtonDefaults.colors(),
interactionSource: MutableInteractionSource? = null,
shapes: IconToggleButtonShapes = IconToggleButtonDefaults.shapes(),
border: BorderStroke? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material IconToggleButton is a filled icon toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for icon or image.
Set the size of the IconToggleButton with Modifier.touchTargetAwareSize to ensure that the background padding will correctly reach the edge of the minimum touch target. The recommended icon toggle button sizes are IconToggleButtonDefaults.Size, IconToggleButtonDefaults.SmallSize, IconToggleButtonDefaults.LargeSize and IconToggleButtonDefaults.ExtraLargeSize.
Use IconToggleButtonDefaults.iconSizeFor to determine the icon size for a given IconToggleButton size, or refer to icon sizes, IconToggleButtonDefaults.DefaultIconSize, IconToggleButtonDefaults.LargeIconSize, IconToggleButtonDefaults.ExtraLargeIconSize directly.
IconToggleButton can be enabled or disabled. A disabled button will not respond to click events. When enabled, the checked and unchecked events are propagated by onCheckedChange.
A simple icon toggle button using the default colors, animated when pressed.
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.IconToggleButton import androidx.wear.compose.material3.IconToggleButtonDefaults import androidx.wear.compose.material3.samples.icons.WifiOffIcon import androidx.wear.compose.material3.samples.icons.WifiOnIcon var firstChecked by remember { mutableStateOf(true) } var secondChecked by remember { mutableStateOf(false) } Row( modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { IconToggleButton( checked = firstChecked, onCheckedChange = { firstChecked = !firstChecked }, shapes = IconToggleButtonDefaults.animatedShapes(), ) { if (firstChecked) { WifiOnIcon() } else { WifiOffIcon() } } Spacer(modifier = Modifier.width(5.dp)) IconToggleButton( checked = secondChecked, onCheckedChange = { secondChecked = !secondChecked }, shapes = IconToggleButtonDefaults.animatedShapes(), ) { if (secondChecked) { WifiOnIcon() } else { WifiOffIcon() } } }
A simple icon toggle button using the default colors, animated when pressed, with different shapes and icons for the checked and unchecked states.
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.IconToggleButton import androidx.wear.compose.material3.IconToggleButtonDefaults import androidx.wear.compose.material3.samples.icons.WifiOffIcon import androidx.wear.compose.material3.samples.icons.WifiOnIcon var firstChecked by remember { mutableStateOf(true) } var secondChecked by remember { mutableStateOf(false) } Row( modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { IconToggleButton( checked = firstChecked, onCheckedChange = { firstChecked = !firstChecked }, shapes = IconToggleButtonDefaults.variantAnimatedShapes(), ) { if (firstChecked) { WifiOnIcon() } else { WifiOffIcon() } } Spacer(modifier = Modifier.width(5.dp)) IconToggleButton( checked = secondChecked, onCheckedChange = { secondChecked = !secondChecked }, shapes = IconToggleButtonDefaults.variantAnimatedShapes(), ) { if (secondChecked) { WifiOnIcon() } else { WifiOffIcon() } } }
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this toggle button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this toggle button is clicked. |
modifier: Modifier = Modifier |
Modifier to be applied to the toggle button. |
enabled: Boolean = true |
Controls the enabled state of the toggle button. When |
colors: IconToggleButtonColors = IconToggleButtonDefaults.colors() |
|
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
shapes: IconToggleButtonShapes = IconToggleButtonDefaults.shapes() |
Defines the shape for this toggle button. Defaults to a static shape based on |
border: BorderStroke? = null |
Optional |
content: @Composable BoxScope.() -> Unit |
The content to be drawn inside the toggle button. |
LevelIndicator
@Composable
fun LevelIndicator(
value: () -> Float,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors(),
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth,
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle,
reverseDirection: Boolean = false
): Unit
Creates a LevelIndicator for screens that that control a setting such as volume with either rotating side button, rotating bezel.
Example of LevelIndicator:
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.padding import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.IconButton import androidx.wear.compose.material3.LevelIndicator import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableFloatStateOf(0.5f) } Box(modifier = Modifier.fillMaxSize()) { Column( verticalArrangement = Arrangement.SpaceEvenly, horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxSize(), ) { IconButton( modifier = Modifier.padding(horizontal = 16.dp), enabled = value < 1f, onClick = { value += 0.1f }, ) { VolumeUpIcon(StepperDefaults.IconSize) } IconButton( modifier = Modifier.padding(horizontal = 16.dp), enabled = value > 0f, onClick = { value -= 0.1f }, ) { VolumeDownIcon(StepperDefaults.IconSize) } } LevelIndicator(value = { value }, modifier = Modifier.align(Alignment.CenterStart)) }
| Parameters | |
|---|---|
value: () -> Float |
Value of the indicator as a fraction in the range 0,1. Values outside of the range 0,1 will be coerced. |
modifier: Modifier = Modifier |
Modifier to be applied to the component |
enabled: Boolean = true |
Controls the enabled state of |
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors() |
|
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth |
The stroke width for the indicator and track strokes |
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle |
The angle covered by the curved LevelIndicator, in degrees |
reverseDirection: Boolean = false |
Reverses direction of PositionIndicator if true |
LinearProgressIndicator
@Composable
fun LinearProgressIndicator(
progress: () -> Float,
modifier: Modifier = Modifier,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge,
enabled: Boolean = true
): Unit
Material Design linear progress indicator.
The LinearProgressIndicator displays progress as a horizontal bar, consisting of two visual components:
-
Track: The background line representing the total range of progress.
-
Indicator: A colored line that fills the track, indicating the current progress value.
The indicator also includes a small dot at the end of the progress line. This dot serves as an accessibility feature to show the range of the indicator.
Progress updates will be animated. Small progress values that are larger than zero will be rounded up to at least the stroke width.
LinearProgressIndicator sample:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.ProgressBarRangeInfo import androidx.compose.ui.semantics.progressBarRangeInfo import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.LinearProgressIndicator import androidx.wear.compose.material3.MaterialTheme Box( modifier = Modifier.background(MaterialTheme.colorScheme.background).fillMaxSize(), contentAlignment = Alignment.Center, ) { LinearProgressIndicator( progress = progress, enabled = enabled, modifier = Modifier.semantics(mergeDescendants = true) { progressBarRangeInfo = ProgressBarRangeInfo(progress(), 0f..1f) }, ) }
| Parameters | |
|---|---|
progress: () -> Float |
The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Values outside of this range are coerced into the range 0..1. Progress value changes will be animated. |
modifier: Modifier = Modifier |
Modifier to be applied to the |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge |
The stroke width for the progress indicator. The minimum value is |
enabled: Boolean = true |
controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is |
ListHeader
@Composable
fun ListHeader(
modifier: Modifier = Modifier,
backgroundColor: Color = Color.Transparent,
contentColor: Color = ListHeaderDefaults.contentColor,
contentPadding: PaddingValues = ListHeaderDefaults.ContentPadding,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
A slot based composable for creating a list header item. ListHeaders are typically expected to be a few words of text on a single line. The contents will be start and end padded.
ListHeader scales itself appropriately when used within the scope of a TransformingLazyColumn.
Example of a ListHeader:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.ListSubHeader import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text val scrollState = rememberScalingLazyListState() ScreenScaffold(scrollState = scrollState, modifier = Modifier.background(Color.Black)) { contentPadding -> ScalingLazyColumn( state = scrollState, modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, contentPadding = contentPadding, ) { item { ListHeader { Text("Settings") } } item { ListSubHeader( icon = { Icon( painter = painterResource(R.drawable.ic_connectivity), contentDescription = "Connectivity", ) }, label = { Text("Connectivity") }, ) } item { Button( modifier = Modifier.fillMaxWidth(), onClick = {}, icon = { Icon( painter = painterResource(R.drawable.ic_bluetooth), contentDescription = "Bluetooth", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, ) { Text("Bluetooth") } } item { Button( modifier = Modifier.fillMaxWidth(), onClick = {}, icon = { Icon( painter = painterResource(R.drawable.ic_wifi), contentDescription = "Wifi", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, ) { Text("Wifi") } } item { ListSubHeader { Text("Display") } } item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Change Watchface") } } item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Brightness") } } } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
The modifier for the |
backgroundColor: Color = Color.Transparent |
The background color to apply - typically Color.Transparent |
contentColor: Color = ListHeaderDefaults.contentColor |
The color to apply to content. |
contentPadding: PaddingValues = ListHeaderDefaults.ContentPadding |
The spacing values to apply internally between the background and the content. |
transformation: SurfaceTransformation? = null |
Transformation to be used when header appears inside the container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for |
ListSubHeader
@Composable
fun ListSubHeader(
modifier: Modifier = Modifier,
backgroundColor: Color = Color.Transparent,
contentColor: Color = ListHeaderDefaults.subHeaderContentColor,
contentPadding: PaddingValues = ListHeaderDefaults.SubHeaderContentPadding,
transformation: SurfaceTransformation? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
A two slot based composable for creating a list sub-header item. ListSubHeaders offer slots for an icon and for a text label. The contents will be start and end padded.
ListSubHeader scales itself appropriately when used within the scope of a TransformingLazyColumn.
Example with use of ListSubHeader:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.ListSubHeader import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text val scrollState = rememberScalingLazyListState() ScreenScaffold(scrollState = scrollState, modifier = Modifier.background(Color.Black)) { contentPadding -> ScalingLazyColumn( state = scrollState, modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, contentPadding = contentPadding, ) { item { ListHeader { Text("Settings") } } item { ListSubHeader( icon = { Icon( painter = painterResource(R.drawable.ic_connectivity), contentDescription = "Connectivity", ) }, label = { Text("Connectivity") }, ) } item { Button( modifier = Modifier.fillMaxWidth(), onClick = {}, icon = { Icon( painter = painterResource(R.drawable.ic_bluetooth), contentDescription = "Bluetooth", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, ) { Text("Bluetooth") } } item { Button( modifier = Modifier.fillMaxWidth(), onClick = {}, icon = { Icon( painter = painterResource(R.drawable.ic_wifi), contentDescription = "Wifi", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, ) { Text("Wifi") } } item { ListSubHeader { Text("Display") } } item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Change Watchface") } } item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Brightness") } } } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
The modifier for the |
backgroundColor: Color = Color.Transparent |
The background color to apply - typically Color.Transparent |
contentColor: Color = ListHeaderDefaults.subHeaderContentColor |
The color to apply to content. |
contentPadding: PaddingValues = ListHeaderDefaults.SubHeaderContentPadding |
The spacing values to apply internally between the background and the content. |
transformation: SurfaceTransformation? = null |
Transformer to be used when header appears inside the container that needs to dynamically change its content separately from the background. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing icon to the |
label: @Composable RowScope.() -> Unit |
A slot for providing label to the |
MaterialTheme
@Composable
fun MaterialTheme(
colorScheme: ColorScheme = MaterialTheme.colorScheme,
typography: Typography = MaterialTheme.typography,
shapes: Shapes = MaterialTheme.shapes,
motionScheme: MotionScheme = MaterialTheme.motionScheme,
content: @Composable () -> Unit
): Unit
MaterialTheme defines the styling principles from the Wear Material3 design specification which extends the Material design specification.
Wear Material components from package/sub-packages in androidx.wear.compose.material3 use values provided here when retrieving default values.
All values may be set by providing this component with the colors, typography, and shapes attributes. Use this to configure the overall theme of elements within this MaterialTheme.
Any values that are not set will inherit the current value from the theme, falling back to the defaults if there is no parent MaterialTheme. This allows using a MaterialTheme at the top of your application, and then separate MaterialTheme(s) for different screens / parts of your UI, overriding only the parts of the theme definition that need to change.
For more information, see the Theming guide.
| Parameters | |
|---|---|
colorScheme: ColorScheme = MaterialTheme.colorScheme |
A complete definition of the Wear Material Color theme for this hierarchy |
typography: Typography = MaterialTheme.typography |
A set of text styles to be used as this hierarchy's typography system |
shapes: Shapes = MaterialTheme.shapes |
A set of shapes to be used by the components in this hierarchy |
motionScheme: MotionScheme = MaterialTheme.motionScheme |
a set of motion specs used to animate content for this hierarchy. |
content: @Composable () -> Unit |
Slot for composable content displayed with this theme |
OpenOnPhoneDialog
@Composable
fun OpenOnPhoneDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors(),
properties: DialogProperties = DialogProperties(),
durationMillis: Long = OpenOnPhoneDialogDefaults.DurationMillis,
content: @Composable () -> Unit = { OpenOnPhoneDialogDefaults.Icon() }
): Unit
A full-screen dialog that displays an animated icon with a curved text at the bottom.
The dialog will be showing a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the dialog, visible parameter should be set to false.
This dialog is typically used to indicate that an action has been initiated and will continue on the user's phone. Once this dialog is displayed, it's developer responsibility to establish the connection between the watch and the phone.
Example of an OpenOnPhoneDialog usage:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.OpenOnPhoneDialog import androidx.wear.compose.material3.OpenOnPhoneDialogDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.openOnPhoneDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Open on phone") }, ) } val text = OpenOnPhoneDialogDefaults.text val style = OpenOnPhoneDialogDefaults.curvedTextStyle OpenOnPhoneDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { openOnPhoneDialogCurvedText(text = text, style = style) }, )
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed - either by swiping right or when the |
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the dialog content. |
colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors() |
|
properties: DialogProperties = DialogProperties() |
An optional |
durationMillis: Long = OpenOnPhoneDialogDefaults.DurationMillis |
The duration in milliseconds for which the dialog is displayed. This value will be adjusted by the accessibility manager according to the content displayed. |
content: @Composable () -> Unit = { OpenOnPhoneDialogDefaults.Icon() } |
A slot for displaying an icon inside the open on phone dialog, which can be animated. Defaults to |
OpenOnPhoneDialogContent
@Composable
fun OpenOnPhoneDialogContent(
curvedText: (CurvedScope.() -> Unit)?,
durationMillis: Long,
modifier: Modifier = Modifier,
colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors(),
content: @Composable () -> Unit
): Unit
This composable provides the content for an OpenOnPhoneDialog that displays an animated icon with curved text at the bottom.
Prefer using OpenOnPhoneDialog directly, which provides built-in animations when showing/hiding the dialog. This composable may be used to provide the content for an openOnPhone dialog if custom show/hide animations are required.
Example of an OpenOnPhoneDialog usage:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.OpenOnPhoneDialog import androidx.wear.compose.material3.OpenOnPhoneDialogDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.openOnPhoneDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Open on phone") }, ) } val text = OpenOnPhoneDialogDefaults.text val style = OpenOnPhoneDialogDefaults.curvedTextStyle OpenOnPhoneDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { openOnPhoneDialogCurvedText(text = text, style = style) }, )
| Parameters | |
|---|---|
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
durationMillis: Long |
The duration in milliseconds for which the progress indicator inside of this content is animated. This value should be previously adjusted by the accessibility manager according to the content displayed. See |
modifier: Modifier = Modifier |
Modifier to be applied to the openOnPhone content. |
colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors() |
|
content: @Composable () -> Unit |
A slot for displaying an icon inside the open on phone dialog, which can be animated. Defaults to |
OutlinedButton
@Composable
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable RowScope.() -> Unit
): Unit
Base level Wear Material3 OutlinedButton that offers a single slot to take any content. Used as the container for more opinionated OutlinedButton components that take specific content such as icons and labels.
The OutlinedButton is Stadium-shaped by default and has a max height designed to take no more than two lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the OutlinedButton height adjusts to accommodate the contents. The OutlinedButton can have an icon or image horizontally parallel to the two lines of text.
OutlinedButton takes the ButtonDefaults.outlinedButtonColors color scheme by default, with a transparent background and a thin border. This is a medium-emphasis button for important, non-primary actions that need attention.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
OutlinedButton can be enabled or disabled. A disabled button will not respond to click events.
Example of an OutlinedButton:
import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.OutlinedButton import androidx.wear.compose.material3.Text OutlinedButton( onClick = { /* Do something */ }, label = { Text("Outlined Button") }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.outlinedButtonColors() |
|
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled) |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable RowScope.() -> Unit |
Slot for composable body content displayed on the OutlinedButton |
OutlinedButton
@Composable
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
label: @Composable RowScope.() -> Unit
): Unit
Wear Material3 OutlinedButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.
The OutlinedButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the OutlinedButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.
If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.
OutlinedButton takes the ButtonDefaults.outlinedButtonColors color scheme by default, with a transparent background and a thin border. This is a medium-emphasis button for important, non-primary actions that need attention.
Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, ChildButton which defaults to ButtonDefaults.childButtonColors. For a background image, see the overload of Button with a containerPainter parameter.
OutlinedButton can be enabled or disabled. A disabled button will not respond to click events.
Example of an OutlinedButton with an icon and secondary label:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.onClick import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.OutlinedButton import androidx.wear.compose.material3.Text OutlinedButton( onClick = { /* Do something */ }, label = { Text("Outlined Button") }, secondaryLabel = { Text("Secondary label") }, icon = { Icon( painter = painterResource(R.drawable.ic_favorite_rounded), contentDescription = "Favorite icon", modifier = Modifier.size(ButtonDefaults.IconSize), ) }, modifier = modifier, )
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button |
modifier: Modifier = Modifier |
Modifier to be applied to the button |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned. |
icon: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = ButtonDefaults.shape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme |
colors: ButtonColors = ButtonDefaults.outlinedButtonColors() |
|
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled) |
Optional |
contentPadding: PaddingValues = ButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. |
OutlinedCard
@Composable
fun OutlinedCard(
modifier: Modifier = Modifier,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.outlinedCardColors(),
border: BorderStroke = CardDefaults.outlinedCardBorder(),
contentPadding: PaddingValues = CardDefaults.ContentPadding,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Outlined Wear Material 3 Card that offers a single slot to take any content.
This OutlinedCard does not handle input events - see the other OutlinedCard overloads if you want a clickable OutlinedCard.
Outlined Card components that take specific content such as icons, images, titles, subtitles and labels. Outlined Cards have a visual boundary around the container. This can emphasise the content of this card.
The OutlinedCard is Rectangle-shaped with rounded corners by default.
Example of a non-clickable OutlinedCard:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.OutlinedCard import androidx.wear.compose.material3.Text OutlinedCard { Text("Non-clickable outlined card") }
For more information, see the Cards Wear OS Material design guide.
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
Modifier to be applied to the card |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.outlinedCardColors() |
|
border: BorderStroke = CardDefaults.outlinedCardBorder() |
A BorderStroke object which is used for the outline drawing. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
OutlinedCard
@Composable
fun OutlinedCard(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.outlinedCardColors(),
border: BorderStroke = CardDefaults.outlinedCardBorder(),
contentPadding: PaddingValues = CardDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: @Composable ColumnScope.() -> Unit
): Unit
Outlined Wear Material 3 Card that offers a single slot to take any content.
Outlined Card components that take specific content such as icons, images, titles, subtitles and labels. Outlined Cards have a visual boundary around the container. This can emphasise the content of this card.
The OutlinedCard is Rectangle-shaped with rounded corners by default.
Cards can be enabled or disabled. A disabled card will not respond to click events.
Example of an OutlinedCard:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.OutlinedCard import androidx.wear.compose.material3.Text OutlinedCard(onClick = { /* Do something */ }) { Text("Outlined card") }
For more information, see the Cards Wear OS Material design guide.
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.outlinedCardColors() |
|
border: BorderStroke = CardDefaults.outlinedCardBorder() |
A BorderStroke object which is used for the outline drawing. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: @Composable ColumnScope.() -> Unit |
The main slot for a content of this card |
OutlinedIconButton
@Composable
fun OutlinedIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shapes: IconButtonShapes = IconButtonDefaults.shapes(),
colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors(),
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
interactionSource: MutableInteractionSource? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material OutlinedIconButton is a circular, icon-only button with a transparent background, contrasting icon color and border. It offers a single slot to take an icon or image.
Set the size of the OutlinedIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.
The recommended icon button sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.
Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.
OutlinedIconButton can be enabled or disabled. A disabled button will not respond to click events.
An OutlinedIconButton has a transparent background and a thin border by default with content taking the theme primary color.
Example of OutlinedIconButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.IconButton import androidx.wear.compose.material3.OutlinedIconButton OutlinedIconButton(onClick = { /* Do something */ }) { Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon") }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shapes: IconButtonShapes = IconButtonDefaults.shapes() |
Defines the shape for this button. Defaults to a static shape based on |
colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors() |
|
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled) |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable BoxScope.() -> Unit |
The content displayed on the icon button, expected to be icon or image. |
Picker
@Composable
fun Picker(
state: PickerState,
contentDescription: (() -> String)?,
modifier: Modifier = Modifier,
readOnly: Boolean = false,
readOnlyLabel: (@Composable BoxScope.() -> Unit)? = null,
onSelected: () -> Unit = {},
verticalSpacing: Dp = 0.dp,
gradientRatio: @FloatRange(from = 0.0, to = 0.5) Float = PickerDefaults.GradientRatio,
gradientColor: Color = MaterialTheme.colorScheme.background,
userScrollEnabled: Boolean = true,
rotaryScrollableBehavior: RotaryScrollableBehavior? = PickerDefaults.rotarySnapBehavior(state),
option: @Composable PickerScope.(index: Int) -> Unit
): Unit
A scrollable list of items to pick from. By default, items will be repeated "infinitely" in both directions, unless PickerState#repeatItems is specified as false.
Picker supports rotary input by default. Rotary input allows users to scroll the content of the Picker - by using a crown or a rotating bezel on their Wear OS device. It can be modified or turned off using the rotaryScrollableBehavior parameter.
Example of a simple picker to select one of five options:
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable 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.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Picker import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberPickerState val items = listOf("One", "Two", "Three", "Four", "Five") val state = rememberPickerState(items.size) // We forward scroll gestures from the whole screen to the Picker which makes this sample // accessible for 2-finger vertical scrolling. Box( modifier = Modifier.fillMaxSize() .scrollable( state = state, orientation = Orientation.Vertical, reverseDirection = true, ), contentAlignment = Alignment.Center, ) { Text( modifier = Modifier.align(Alignment.TopCenter).padding(top = 10.dp), text = "Selected: ${items[state.selectedOptionIndex]}", ) Picker( modifier = Modifier.size(100.dp, 100.dp), state = state, contentDescription = { "${state.selectedOptionIndex + 1}" }, ) { Text(items[it]) } }
Example of a sample picker group with an hour and minute picker (24 hour format):
import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.PickerGroup import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberPickerState var selectedPickerIndex by remember { mutableIntStateOf(0) } val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24) val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60) Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(modifier = Modifier.size(30.dp)) val label = if (selectedPickerIndex == 0) "Hours" else "Minutes" AnimatedContent(targetState = label) { targetText -> Text(text = targetText) } Spacer(modifier = Modifier.size(10.dp)) PickerGroup( selectedPickerState = if (selectedPickerIndex == 0) pickerStateHour else pickerStateMinute, autoCenter = false, ) { PickerGroupItem( pickerState = pickerStateHour, selected = selectedPickerIndex == 0, onSelected = { selectedPickerIndex = 0 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Hours" }, modifier = Modifier.size(80.dp, 100.dp), ) PickerGroupItem( pickerState = pickerStateMinute, selected = selectedPickerIndex == 1, onSelected = { selectedPickerIndex = 1 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Minutes" }, modifier = Modifier.size(80.dp, 100.dp), ) } }
| Parameters | |
|---|---|
state: PickerState |
The state of the component |
contentDescription: (() -> String)? |
A block which computes text used by accessibility services to describe what the selected option represents. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar. |
modifier: Modifier = Modifier |
|
readOnly: Boolean = false |
Determines whether the |
readOnlyLabel: (@Composable BoxScope.() -> Unit)? = null |
A slot for providing a label, displayed above the selected option when the |
onSelected: () -> Unit = {} |
Action triggered when the Picker is selected by clicking. Used by accessibility semantics, which facilitates implementation of multi-picker screens. |
verticalSpacing: Dp = 0.dp |
The amount of vertical spacing in |
gradientRatio: @FloatRange(from = 0.0, to = 0.5) Float = PickerDefaults.GradientRatio |
The size relative to the Picker height that the top and bottom gradients take. These gradients blur the picker content on the top and bottom. The default is 0.33, so the top 1/3 and the bottom 1/3 of the picker are taken by gradients. Should be between 0.0 and 0.5. Use 0.0 to disable the gradient. |
gradientColor: Color = MaterialTheme.colorScheme.background |
Should be the color outside of the Picker, so there is continuity. |
userScrollEnabled: Boolean = true |
Determines whether the picker should be scrollable or not. When userScrollEnabled = true, picker is scrollable. This is different from |
rotaryScrollableBehavior: RotaryScrollableBehavior? = PickerDefaults.rotarySnapBehavior(state) |
Parameter for changing rotary behavior. We recommend to use |
option: @Composable PickerScope.(index: Int) -> Unit |
A block which describes the content. Inside this block you can reference |
PickerGroup
@Composable
fun PickerGroup(
modifier: Modifier = Modifier,
selectedPickerState: PickerState? = null,
autoCenter: Boolean = true,
propagateMinConstraints: Boolean = false,
content: @Composable PickerGroupScope.() -> Unit
): Unit
A group of Pickers to build components where multiple pickers are required to be combined together. At most one Picker can be selected at a time. When touch exploration services are enabled, the focus moves to the picker which is clicked.
It is recommended to ensure that a Picker in non read only mode should have user scroll enabled when touch exploration services are running.
Example of a sample picker group with an hour and minute picker (24 hour format):
import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.PickerGroup import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberPickerState var selectedPickerIndex by remember { mutableIntStateOf(0) } val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24) val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60) Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(modifier = Modifier.size(30.dp)) val label = if (selectedPickerIndex == 0) "Hours" else "Minutes" AnimatedContent(targetState = label) { targetText -> Text(text = targetText) } Spacer(modifier = Modifier.size(10.dp)) PickerGroup( selectedPickerState = if (selectedPickerIndex == 0) pickerStateHour else pickerStateMinute, autoCenter = false, ) { PickerGroupItem( pickerState = pickerStateHour, selected = selectedPickerIndex == 0, onSelected = { selectedPickerIndex = 0 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Hours" }, modifier = Modifier.size(80.dp, 100.dp), ) PickerGroupItem( pickerState = pickerStateMinute, selected = selectedPickerIndex == 1, onSelected = { selectedPickerIndex = 1 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Minutes" }, modifier = Modifier.size(80.dp, 100.dp), ) } }
Example of an auto centering picker group where the total width exceeds screen's width:
import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.PickerGroup import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberPickerState var selectedPickerIndex by remember { mutableIntStateOf(0) } val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24) val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60) val pickerStateSeconds = rememberPickerState(initialNumberOfOptions = 60) val pickerStateMilliSeconds = rememberPickerState(initialNumberOfOptions = 1000) val pickerStates = remember { arrayOf(pickerStateHour, pickerStateMinute, pickerStateSeconds, pickerStateMilliSeconds) } Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { val headingText = mapOf(0 to "Hours", 1 to "Minutes", 2 to "Seconds", 3 to "Milli") Spacer(modifier = Modifier.size(30.dp)) AnimatedContent(targetState = headingText[selectedPickerIndex]!!) { targetText -> Text(text = targetText) } Spacer(modifier = Modifier.size(10.dp)) PickerGroup(selectedPickerState = pickerStates[selectedPickerIndex], autoCenter = true) { PickerGroupItem( pickerState = pickerStateHour, selected = selectedPickerIndex == 0, onSelected = { selectedPickerIndex = 0 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Hours" }, modifier = Modifier.size(80.dp, 100.dp), ) PickerGroupItem( pickerState = pickerStateMinute, selected = selectedPickerIndex == 1, onSelected = { selectedPickerIndex = 1 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Minutes" }, modifier = Modifier.size(80.dp, 100.dp), ) PickerGroupItem( pickerState = pickerStateSeconds, selected = selectedPickerIndex == 2, onSelected = { selectedPickerIndex = 2 }, option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) }, contentDescription = { "Seconds" }, modifier = Modifier.size(80.dp, 100.dp), ) PickerGroupItem( pickerState = pickerStateMilliSeconds, selected = selectedPickerIndex == 3, onSelected = { selectedPickerIndex = 3 }, option = { optionIndex, _ -> Text(text = "%03d".format(optionIndex)) }, contentDescription = { "Milliseconds" }, modifier = Modifier.size(80.dp, 100.dp), ) } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
|
selectedPickerState: PickerState? = null |
The |
autoCenter: Boolean = true |
Indicates whether the selected |
propagateMinConstraints: Boolean = false |
Whether the incoming min constraints should be passed to content. |
content: @Composable PickerGroupScope.() -> Unit |
The content of the |
ProvideTextStyle
@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit): Unit
This function is used to set the current value of LocalTextStyle, merging the given style with the current style values for any missing attributes. Any Text components included in this component's content will be styled with this style unless styled explicitly.
| See also | |
|---|---|
LocalTextStyle |
RadioButton
@Composable
fun RadioButton(
selected: Boolean,
onSelect: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = RadioButtonDefaults.radioButtonShape,
colors: RadioButtonColors = RadioButtonDefaults.radioButtonColors(),
contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material RadioButton offers slots and a specific layout for an icon, a label and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start, a column containing the two label slots in the middle and the selection control at the end.
The RadioButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the RadioButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
Note that Modifier.selectableGroup() must be present on the parent control (such as Column) to ensure correct accessibility behavior.
Samples: Example of a RadioButton:
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RadioButton import androidx.wear.compose.material3.Text Column(modifier = Modifier.selectableGroup().fillMaxSize()) { var selectedButton by remember { mutableStateOf(0) } // RadioButton uses the Radio selection control by default. RadioButton( label = { Text("Radio button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, secondaryLabel = { Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis) }, selected = selectedButton == 0, onSelect = { selectedButton = 0 }, icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") }, enabled = true, ) Spacer(modifier = Modifier.height(4.dp)) RadioButton( label = { Text("Radio button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, secondaryLabel = { Text("With secondary label", maxLines = 3, overflow = TextOverflow.Ellipsis) }, selected = selectedButton == 1, onSelect = { selectedButton = 1 }, icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") }, enabled = true, ) }
RadioButton can be enabled or disabled. A disabled button will not respond to click events.
The recommended set of RadioButton colors can be obtained from RadioButtonDefaults, e.g. RadioButtonDefaults.radioButtonColors.
| Parameters | |
|---|---|
selected: Boolean |
Boolean flag indicating whether this button is currently selected. |
onSelect: () -> Unit |
Callback to be invoked when this button has been selected by clicking. |
modifier: Modifier = Modifier |
Modifier to be applied to the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = RadioButtonDefaults.radioButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: RadioButtonColors = RadioButtonDefaults.radioButtonColors() |
|
contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
icon: (@Composable BoxScope.() -> Unit)? = null |
An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be center-aligned, both horizontally and vertically, and should be an icon of size 24.dp. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned. |
ScreenScaffold
@Composable
fun ScreenScaffold(
modifier: Modifier = Modifier,
scrollInfoProvider: ScrollInfoProvider? = null,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = null,
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollInfoProvider.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
scrollInfoProvider: ScrollInfoProvider? = null |
Provider for scroll information used to scroll away screen elements such as |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = null |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: LazyListState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: LazyListState |
The scroll state for |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: ScalingLazyListState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: ScalingLazyListState |
The scroll state for |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: ScrollState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState. Note that this version doesn't support a bottom button slot, for that use the overload that takes LazyListState or the one that takes a ScalingLazyListState.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: ScrollState |
The scroll state for a Column, used to drive screen transitions such as |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: TransformingLazyColumnState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
Example of using AppScaffold and ScreenScaffold:
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold(scrollState = listState, contentPadding = PaddingValues(10.dp)) { contentPadding -> ScalingLazyColumn( state = listState, contentPadding = contentPadding, modifier = Modifier.fillMaxSize(), ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: TransformingLazyColumnState |
The scroll state for |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollInfoProvider: ScrollInfoProvider,
edgeButton: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = null,
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing,
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText, ScrollIndicator and the bottom button according to a scrollInfoProvider.
This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content. In this overload, both edgeButton and scrollInfoProvider must be specified.
| Parameters | |
|---|---|
scrollInfoProvider: ScrollInfoProvider |
Provider for scroll information used to scroll away screen elements such as |
edgeButton: @Composable BoxScope.() -> Unit |
slot for a |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = null |
The |
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing |
The space between |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: LazyListState,
edgeButton: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing,
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.
Example of using AppScaffold and ScreenScaffold with ScalingLazyColumn:
import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold(modifier = Modifier.background(Color.Black)) { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold( scrollState = listState, // Define custom spacing between [EdgeButton] and [ScalingLazyColumn]. edgeButtonSpacing = 15.dp, edgeButton = { EdgeButton( onClick = {}, modifier = // In case user starts scrolling from the EdgeButton. Modifier.scrollable( listState, orientation = Orientation.Vertical, reverseDirection = true, // An overscroll effect should be applied to the EdgeButton for proper // scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text("Clear All") } }, ) { contentPadding -> ScalingLazyColumn( state = listState, modifier = Modifier.fillMaxSize(), // Bottom spacing is derived from [ScreenScaffold.edgeButtonSpacing]. contentPadding = contentPadding, autoCentering = null, ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: LazyListState |
The scroll state for |
edgeButton: @Composable BoxScope.() -> Unit |
Slot for an |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing |
The space between |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: ScalingLazyListState,
edgeButton: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing,
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.
When using ScreenScaffold with EdgeButton and ScalingLazyColumn, you should pass autoCentering = null for the ScalingLazyColumn in order to achieve the correct spacing above the EdgeButton.
Example of using AppScaffold and ScreenScaffold with ScalingLazyColumn:
import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold(modifier = Modifier.background(Color.Black)) { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberScalingLazyListState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold( scrollState = listState, // Define custom spacing between [EdgeButton] and [ScalingLazyColumn]. edgeButtonSpacing = 15.dp, edgeButton = { EdgeButton( onClick = {}, modifier = // In case user starts scrolling from the EdgeButton. Modifier.scrollable( listState, orientation = Orientation.Vertical, reverseDirection = true, // An overscroll effect should be applied to the EdgeButton for proper // scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text("Clear All") } }, ) { contentPadding -> ScalingLazyColumn( state = listState, modifier = Modifier.fillMaxSize(), // Bottom spacing is derived from [ScreenScaffold.edgeButtonSpacing]. contentPadding = contentPadding, autoCentering = null, ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
| Parameters | |
|---|---|
scrollState: ScalingLazyListState |
The scroll state for |
edgeButton: @Composable BoxScope.() -> Unit |
Slot for an |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing |
The space between |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScreenScaffold
@Composable
fun ScreenScaffold(
scrollState: TransformingLazyColumnState,
edgeButton: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding,
timeText: (@Composable () -> Unit)? = null,
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) },
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing,
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
content: @Composable BoxScope.(PaddingValues) -> Unit
): Unit
ScreenScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.
ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.
This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.
Example of using AppScaffold and ScreenScaffold with TransformingLazyColumn:
import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text // Declare just one [AppScaffold] per app such as in the activity. // [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible // during in-app transitions such as swipe-to-dismiss. AppScaffold(modifier = Modifier.background(Color.Black)) { // Define the navigation hierarchy within the AppScaffold, // such as using SwipeDismissableNavHost. // For this sample, we will define a single screen inline. val listState = rememberTransformingLazyColumnState() // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator, // showing/hiding/scrolling away TimeText and optionally hosting the EdgeButton. ScreenScaffold( scrollState = listState, // Define custom spacing between [EdgeButton] and [ScalingLazyColumn]. edgeButtonSpacing = 15.dp, edgeButton = { EdgeButton( onClick = {}, modifier = // In case user starts scrolling from the EdgeButton. Modifier.scrollable( listState, orientation = Orientation.Vertical, reverseDirection = true, // An overscroll effect should be applied to the EdgeButton for proper // scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text("Clear All") } }, ) { contentPadding -> TransformingLazyColumn( state = listState, modifier = Modifier.fillMaxSize(), // Bottom spacing is derived from [ScreenScaffold.edgeButtonSpacing]. contentPadding = contentPadding, ) { items(10) { Button(onClick = {}, label = { Text("Item ${it + 1}") }) } } } }
Example of using ScreenScaffold with a EdgeButton:
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.EdgeButtonSize import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RadioButton import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.CheckIcon val state = rememberScalingLazyListState() val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f val verticalPadding = LocalConfiguration.current.screenHeightDp.dp * 0.16f val colors = listOf( "Filled" to ButtonDefaults.buttonColors(), "Filled Variant" to ButtonDefaults.filledVariantButtonColors(), "Filled Tonal" to ButtonDefaults.filledTonalButtonColors(), "Outlined" to ButtonDefaults.outlinedButtonColors(), "Disabled" to ButtonDefaults.buttonColors(), ) var selectedColor by remember { mutableIntStateOf(0) } val types = listOf("Icon only" to 0, "Text only" to 1) var selectedType by remember { mutableIntStateOf(0) } ScreenScaffold( scrollState = state, contentPadding = PaddingValues(horizontal = horizontalPadding, vertical = verticalPadding), edgeButton = { EdgeButton( modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // An overscroll effect should be applied to the EdgeButton for proper // scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), onClick = {}, buttonSize = EdgeButtonSize.Medium, colors = colors[selectedColor].second, border = if (colors[selectedColor].first == "Outlined") ButtonDefaults.outlinedButtonBorder(true) else null, enabled = colors[selectedColor].first != "Disabled", ) { if (selectedType == 0) { // Remove extra spacing around the icon so it integrates better into the scroll. CheckIcon(Modifier.size(21.dp).wrapContentSize(unbounded = true).size(32.dp)) } else { Text("Ok") } } }, ) { contentPadding -> ScalingLazyColumn( state = state, modifier = Modifier.fillMaxSize().selectableGroup(), autoCentering = null, contentPadding = contentPadding, horizontalAlignment = Alignment.CenterHorizontally, ) { item { Text("Color") } items(colors.size) { ix -> RadioButton( label = { Text(colors[ix].first) }, selected = selectedColor == ix, onSelect = { selectedColor = ix }, modifier = Modifier.fillMaxWidth(), ) } item { Text("Type") } items(types.size) { ix -> RadioButton( label = { Text(types[ix].first) }, selected = selectedType == ix, onSelect = { selectedType = ix }, modifier = Modifier.fillMaxWidth(), ) } } }
| Parameters | |
|---|---|
scrollState: TransformingLazyColumnState |
The scroll state for |
edgeButton: @Composable BoxScope.() -> Unit |
Slot for an |
modifier: Modifier = Modifier |
The modifier for the screen scaffold. |
contentPadding: PaddingValues = ScreenScaffoldDefaults.contentPadding |
The padding to apply around the entire content. This contentPadding is then received by the |
timeText: (@Composable () -> Unit)? = null |
Time text (both time and potentially status message) for this screen, if different to the time text at the |
scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState) } |
The |
edgeButtonSpacing: Dp = ScreenScaffoldDefaults.EdgeButtonSpacing |
The space between |
overscrollEffect: OverscrollEffect? = rememberOverscrollEffect() |
the |
content: @Composable BoxScope.(PaddingValues) -> Unit |
The body content for this screen. The lambda receives a |
ScrollIndicator
@Composable
fun ScrollIndicator(
state: LazyListState,
modifier: Modifier = Modifier,
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors(),
reverseDirection: Boolean = state.layoutInfo.reverseLayout,
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit
A composable that displays a visual indicator of scrolling progress within a scrollable container.
Creates an ScrollIndicator based on the values in a LazyListState object that a LazyColumn uses.
To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd. It will appear on the right in Ltr orientation and on the left in Rtl orientation.
It detects if the screen is round or square and draws itself as a curve or line.
For more information, see the Scroll indicators guide.
Example of a sample ScrollIndicator with LazyColumn:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ScrollIndicator import androidx.wear.compose.material3.Text val scrollState = rememberLazyListState() Box { LazyColumn( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, state = scrollState, ) { items(100) { Text(text = "Item $it") } } ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState) }
| Parameters | |
|---|---|
state: LazyListState |
the |
modifier: Modifier = Modifier |
The modifier to be applied to the component |
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors() |
|
reverseDirection: Boolean = state.layoutInfo.reverseLayout |
Reverses direction of ScrollIndicator if true. The default value is inferred from the |
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec |
|
ScrollIndicator
@Composable
fun ScrollIndicator(
state: ScalingLazyListState,
modifier: Modifier = Modifier,
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors(),
reverseDirection: Boolean = state.layoutInfo.reverseLayout,
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit
A composable that displays a visual indicator of scrolling progress within a scrollable container.
Creates an ScrollIndicator based on the values in a ScalingLazyListState object that a ScalingLazyColumn uses.
Typically used with the ScreenScaffold but can be used to decorate any full screen situation.
To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd. It will appear on the right in Ltr orientation and on the left in Rtl orientation.
It detects if the screen is round or square and draws itself as a curve or line.
For more information, see the Scroll indicators guide.
Example of a sample ScrollIndicator with ScalingLazyColumn:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.ScrollIndicator import androidx.wear.compose.material3.Text val scrollState = rememberScalingLazyListState() Box { ScalingLazyColumn(modifier = Modifier.fillMaxSize(), state = scrollState) { items(100) { Text(text = "Item $it") } } ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState) }
| Parameters | |
|---|---|
state: ScalingLazyListState |
the |
modifier: Modifier = Modifier |
The modifier to be applied to the component |
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors() |
|
reverseDirection: Boolean = state.layoutInfo.reverseLayout |
Reverses direction of ScrollIndicator if true. The default value is inferred from the |
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec |
|
ScrollIndicator
@Composable
fun ScrollIndicator(
state: ScrollState,
modifier: Modifier = Modifier,
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors(),
reverseDirection: Boolean = false,
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit
A composable that displays a visual indicator of scrolling progress within a scrollable container.
Creates a ScrollIndicator based on the values in a ScrollState object. e.g. a Column implementing Modifier.verticalScroll provides a ScrollState.
To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd, such as by setting modifier = Modifier.align(Alignment.CenterEnd). This way, the ScrollIndicator will appear on the right in Ltr orientation and on the left in Rtl orientation.
It detects if the screen is round or square and draws itself as a curve or line.
For more information, see the Scroll indicators guide.
Example of a sample ScrollIndicator with Column:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ScrollIndicator import androidx.wear.compose.material3.Text val scrollState = rememberScrollState() Box { Column( modifier = Modifier.fillMaxSize().verticalScroll(scrollState), horizontalAlignment = Alignment.CenterHorizontally, ) { repeat(100) { Text(text = "Item $it") } } ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState) }
| Parameters | |
|---|---|
state: ScrollState |
The scrollState to use as the basis for the ScrollIndicatorState. |
modifier: Modifier = Modifier |
The modifier to be applied to the component - usually set to |
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors() |
|
reverseDirection: Boolean = false |
Reverses direction of ScrollIndicator if true |
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec |
|
ScrollIndicator
@Composable
fun ScrollIndicator(
state: TransformingLazyColumnState,
modifier: Modifier = Modifier,
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors(),
reverseDirection: Boolean = state.layoutInfo.reverseLayout,
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit
A composable that displays a visual indicator of scrolling progress within a scrollable container.
Creates an ScrollIndicator based on the values in a TransformingLazyColumnState object that a TransformingLazyColumn uses.
Typically used with the ScreenScaffold but can be used to decorate any full screen situation.
To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd. It will appear on the right in Ltr orientation and on the left in Rtl orientation.
It detects if the screen is round or square and draws itself as a curve or line.
For more information, see the Scroll indicators guide.
Example of a sample ScrollIndicator with TransformingLazyColumn:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState import androidx.wear.compose.material3.ScrollIndicator import androidx.wear.compose.material3.Text val scrollState = rememberTransformingLazyColumnState() Box { TransformingLazyColumn(modifier = Modifier.background(Color.Black), state = scrollState) { items(100) { Text(text = "Item $it") } } ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState) }
| Parameters | |
|---|---|
state: TransformingLazyColumnState |
the |
modifier: Modifier = Modifier |
The modifier to be applied to the component |
colors: ScrollIndicatorColors = ScrollIndicatorDefaults.colors() |
|
reverseDirection: Boolean = state.layoutInfo.reverseLayout |
Reverses direction of ScrollIndicator if true. The default value is inferred from the |
positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec |
|
SegmentedCircularProgressIndicator
@Composable
fun SegmentedCircularProgressIndicator(
segmentCount: @IntRange(from = 1) Int,
segmentValue: (segmentIndex: Int) -> Boolean,
modifier: Modifier = Modifier,
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
endAngle: Float = startAngle,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
enabled: Boolean = true
): Unit
Material Design segmented circular progress indicator.
A segmented variant of CircularProgressIndicator that is divided into equally sized segments. This overload of SegmentedCircularProgressIndicator allows for each segment to be individually indicated as completed, such as for showing activity for intervals within a longer period
Example of SegmentedCircularProgressIndicator where the segments are turned on/off:
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.ui.Modifier import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ProgressIndicatorDefaults import androidx.wear.compose.material3.SegmentedCircularProgressIndicator Box( modifier = Modifier.background(MaterialTheme.colorScheme.background) .padding(CircularProgressIndicatorDefaults.FullScreenPadding) .fillMaxSize() ) { SegmentedCircularProgressIndicator(segmentCount = 5, segmentValue = { it % 2 != 0 }) }
Example of smaller size SegmentedCircularProgressIndicator:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.SegmentedCircularProgressIndicator Box(modifier = Modifier.fillMaxSize()) { SegmentedCircularProgressIndicator( segmentCount = 8, segmentValue = { it % 2 != 0 }, modifier = Modifier.align(Alignment.Center).size(80.dp), ) }
| Parameters | |
|---|---|
segmentCount: @IntRange(from = 1) Int |
Number of equal segments that the progress indicator should be divided into. Has to be a number equal or greater to 1. |
segmentValue: (segmentIndex: Int) -> Boolean |
A function that for each segment between 1.. |
modifier: Modifier = Modifier |
Modifier to be applied to the SegmentedCircularProgressIndicator. |
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle |
The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees |
endAngle: Float = startAngle |
The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth |
The stroke width for the progress indicator. |
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size of the gap between segments (in Dp). |
enabled: Boolean = true |
controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is |
SegmentedCircularProgressIndicator
@Composable
fun SegmentedCircularProgressIndicator(
segmentCount: @IntRange(from = 1) Int,
progress: () -> Float,
modifier: Modifier = Modifier,
allowProgressOverflow: Boolean = false,
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
endAngle: Float = startAngle,
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
enabled: Boolean = true
): Unit
Material Design segmented circular progress indicator.
A segmented variant of CircularProgressIndicator that is divided into equally sized segments.
Example of SegmentedCircularProgressIndicator with progress value:
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.ui.Modifier import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ProgressIndicatorDefaults import androidx.wear.compose.material3.SegmentedCircularProgressIndicator Box( modifier = Modifier.background(MaterialTheme.colorScheme.background) .padding(CircularProgressIndicatorDefaults.FullScreenPadding) .fillMaxSize() ) { SegmentedCircularProgressIndicator(segmentCount = 5, progress = { 0.5f }) }
Example of smaller size SegmentedCircularProgressIndicator:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.SegmentedCircularProgressIndicator Box(modifier = Modifier.fillMaxSize()) { SegmentedCircularProgressIndicator( segmentCount = 6, progress = { 0.75f }, modifier = Modifier.align(Alignment.Center).size(80.dp), ) }
| Parameters | |
|---|---|
segmentCount: @IntRange(from = 1) Int |
Number of equal segments that the progress indicator should be divided into. Has to be a number equal or greater to 1. |
progress: () -> Float |
The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color. The progress is applied to the entire |
modifier: Modifier = Modifier |
Modifier to be applied to the SegmentedCircularProgressIndicator. |
allowProgressOverflow: Boolean = false |
When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color |
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle |
The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees |
endAngle: Float = startAngle |
The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to |
colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors() |
|
strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth |
The stroke width for the progress indicator. |
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size of the gap between segments (in Dp). |
enabled: Boolean = true |
controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is |
Slider
@Composable
fun Slider(
value: Int,
onValueChange: (Int) -> Unit,
valueProgression: IntProgression,
modifier: Modifier = Modifier,
decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() },
increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() },
enabled: Boolean = true,
segmented: Boolean = valueProgression.stepsNumber() <= MaxSegmentSteps,
shape: Shape = SliderDefaults.shape,
colors: SliderColors = SliderDefaults.sliderColors()
): Unit
Slider allows users to make a selection from a range of values. The range of selections is shown as a bar between the minimum and maximum values of the range, from which users may select a single value. Slider is ideal for adjusting settings such as volume or brightness.
Value can be increased and decreased by clicking on the increase and decrease buttons, located accordingly to the start and end of the control. Buttons can have custom icons - decreaseIcon and increaseIcon.
The bar in the middle of control can have separators if segmented flag is set to true. A number of steps is calculated as the difference between max and min values of valueProgression divided by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of steps will be (120-100)/ 5 - 1 = 3. Steps are 100(first), 105, 110, 115, 120(last)
If valueProgression range is not equally divisible by valueProgression.step, then valueProgression.last will be adjusted to the closest divisible value in the range. For example, 1..13 range and a step = 5, steps will be 1(first) , 6 , 11(last)
A continuous non-segmented slider sample:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Slider var value by remember { mutableStateOf(4) } Slider( value = value, onValueChange = { value = it }, valueProgression = 0..10, segmented = false, )
A segmented slider sample:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Slider var value by remember { mutableStateOf(2f) } Slider( value = value, onValueChange = { value = it }, valueRange = 1f..4f, steps = 7, segmented = true, )
| Parameters | |
|---|---|
value: Int |
Current value of the Slider. If outside of |
onValueChange: (Int) -> Unit |
Lambda in which value should be updated. |
valueProgression: IntProgression |
Progression of values that Slider value can take. Consists of rangeStart, rangeEnd and step. Range will be equally divided by step size. |
modifier: Modifier = Modifier |
Modifiers for the Slider layout. |
decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() } |
A slot for an icon which is placed on the decrease (start) button such as |
increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() } |
A slot for an icon which is placed on the increase (end) button such as |
enabled: Boolean = true |
Controls the enabled state of the slider. When |
segmented: Boolean = valueProgression.stepsNumber() <= MaxSegmentSteps |
A boolean value which specifies whether a bar will be split into segments or not. Recommendation is while using this flag do not have more than |
shape: Shape = SliderDefaults.shape |
Defines slider's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme. |
colors: SliderColors = SliderDefaults.sliderColors() |
|
Slider
@Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
steps: Int,
modifier: Modifier = Modifier,
decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() },
increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() },
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat(),
segmented: Boolean = steps <= MaxSegmentSteps,
shape: Shape = SliderDefaults.shape,
colors: SliderColors = SliderDefaults.sliderColors()
): Unit
Slider allows users to make a selection from a range of values. The range of selections is shown as a bar between the minimum and maximum values of the range, from which users may select a single value. Slider is ideal for adjusting settings such as volume or brightness.
Value can be increased and decreased by clicking on the increase and decrease buttons, located accordingly to the start and end of the control. Buttons can have custom icons - decreaseIcon and increaseIcon.
The bar in the middle of control can have separators if segmented flag is set to true. A single step value is calculated as the difference between min and max values of valueRange divided by steps + 1 value.
A continuous non-segmented slider sample:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Slider var value by remember { mutableStateOf(4.5f) } Slider( value = value, onValueChange = { value = it }, valueRange = 3f..6f, steps = 5, segmented = false, )
A segmented slider sample:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Slider var value by remember { mutableStateOf(2f) } Slider( value = value, onValueChange = { value = it }, valueRange = 1f..4f, steps = 7, segmented = true, )
| Parameters | |
|---|---|
value: Float |
Current value of the Slider. If outside of |
onValueChange: (Float) -> Unit |
Lambda in which value should be updated. |
steps: Int |
Specifies the number of discrete values, excluding min and max values, evenly distributed across the whole value range. Must not be negative. If 0, slider will have only min and max values and no steps in between. |
modifier: Modifier = Modifier |
Modifiers for the Slider layout. |
decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() } |
A slot for an icon which is placed on the decrease (start) button such as |
increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() } |
A slot for an icon which is placed on the increase (end) button such as |
enabled: Boolean = true |
Controls the enabled state of the slider. When |
valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat() |
Range of values that Slider value can take. Passed |
segmented: Boolean = steps <= MaxSegmentSteps |
A boolean value which specifies whether a bar will be split into segments or not. Recommendation is while using this flag do not have more than |
shape: Shape = SliderDefaults.shape |
Defines slider's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme. |
colors: SliderColors = SliderDefaults.sliderColors() |
|
SplitCheckboxButton
@Composable
fun SplitCheckboxButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
toggleContentDescription: String?,
onContainerClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = CheckboxButtonDefaults.splitCheckboxButtonShape,
colors: SplitCheckboxButtonColors = CheckboxButtonDefaults.splitCheckboxButtonColors(),
toggleInteractionSource: MutableInteractionSource? = null,
containerInteractionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
containerClickLabel: String? = null,
contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material SplitCheckboxButton offers slots and a specific layout for a label and secondaryLabel. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and a Checkbox at the end.
The SplitCheckboxButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitCheckboxButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
A SplitCheckboxButton has two tappable areas, one tap area for the labels and another for the checkbox. The onContainerClick listener will be associated with the main body of the SplitCheckboxButton and the onCheckedChange listener associated with the checkbox area only.
Samples: Example of a SplitCheckboxButton:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.CheckboxButton import androidx.wear.compose.material3.SplitCheckboxButton import androidx.wear.compose.material3.Text var checked by remember { mutableStateOf(true) } SplitCheckboxButton( label = { Text("Split Checkbox Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, checked = checked, onCheckedChange = { checked = it }, toggleContentDescription = "Split Checkbox Button Sample", onContainerClick = { /* Do something */ }, containerClickLabel = "click", enabled = true, )
For a SplitCheckboxButton the background of the tappable background area behind the toggle control will have a visual effect applied to provide a "divider" between the two tappable areas.
The recommended set of colors can be obtained from CheckboxButtonDefaults, e.g. CheckboxButtonDefaults.splitCheckboxButtonColors.
SplitCheckboxButton can be enabled or disabled. A disabled button will not respond to click events.
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this buttons checked status is changed. |
toggleContentDescription: String? |
The content description for the checkbox control part of the component. |
onContainerClick: () -> Unit |
Click listener called when the user clicks the main body of the button, the area behind the labels. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = CheckboxButtonDefaults.splitCheckboxButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: SplitCheckboxButtonColors = CheckboxButtonDefaults.splitCheckboxButtonColors() |
|
toggleInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
containerInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
containerClickLabel: String? = null |
Optional click label on the main body of the button for accessibility. |
contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be "start" aligned. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned. |
SplitRadioButton
@Composable
fun SplitRadioButton(
selected: Boolean,
onSelectionClick: () -> Unit,
selectionContentDescription: String?,
onContainerClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = RadioButtonDefaults.splitRadioButtonShape,
colors: SplitRadioButtonColors = RadioButtonDefaults.splitRadioButtonColors(),
selectionInteractionSource: MutableInteractionSource? = null,
containerInteractionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
containerClickLabel: String? = null,
contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material SplitRadioButton offers two slots and a specific layout for a label and secondaryLabel. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and radio button control at the end.
The SplitRadioButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitRadioButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
A SplitRadioButton has two tappable areas, one tap area for the labels and another for the selection control. The onContainerClick listener will be associated with the main body of the split radio button with the onSelectionClick listener associated with the selection control area only.
Samples: Example of a SplitRadioButton:
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.selection.selectableGroup import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.RadioButton import androidx.wear.compose.material3.SplitRadioButton import androidx.wear.compose.material3.Text Column(modifier = Modifier.selectableGroup()) { var selectedButton by remember { mutableStateOf(0) } // SplitRadioButton uses the Radio selection control by default. SplitRadioButton( label = { Text("First Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, selected = selectedButton == 0, onSelectionClick = { selectedButton = 0 }, selectionContentDescription = "First", onContainerClick = { /* Do something */ }, containerClickLabel = "click", enabled = true, ) Spacer(modifier = Modifier.height(4.dp)) SplitRadioButton( label = { Text("Second Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, selected = selectedButton == 1, onSelectionClick = { selectedButton = 1 }, selectionContentDescription = "Second", onContainerClick = { /* Do something */ }, containerClickLabel = "click", enabled = true, ) }
For a SplitRadioButton the background of the tappable background area behind the selection control will have a visual effect applied to provide a "divider" between the two tappable areas.
The recommended set of colors can be obtained from RadioButtonDefaults, e.g. RadioButtonDefaults.splitRadioButtonColors.
SplitRadioButton can be enabled or disabled. A disabled button will not respond to click events.
| Parameters | |
|---|---|
selected: Boolean |
Boolean flag indicating whether this button is currently selected. |
onSelectionClick: () -> Unit |
Callback to be invoked when this button has been selected. |
selectionContentDescription: String? |
The content description for the selection control part of the component |
onContainerClick: () -> Unit |
Click listener called when the user clicks the main body of the button, the area containing the labels. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = RadioButtonDefaults.splitRadioButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: SplitRadioButtonColors = RadioButtonDefaults.splitRadioButtonColors() |
|
selectionInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
containerInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
containerClickLabel: String? = null |
Optional click label on the main body of the button for accessibility. |
contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be "start" aligned. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned. |
SplitSwitchButton
@Composable
fun SplitSwitchButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
toggleContentDescription: String?,
onContainerClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = SwitchButtonDefaults.splitSwitchButtonShape,
colors: SplitSwitchButtonColors = SwitchButtonDefaults.splitSwitchButtonColors(),
toggleInteractionSource: MutableInteractionSource? = null,
containerInteractionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
containerClickLabel: String? = null,
contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material SplitSwitchButton offers slots and a specific layout for a label and secondary label. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and a Switch at the end.
The SplitSwitchButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitSwitchButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
A SplitSwitchButton has two tappable areas, one tap area for the labels and another for the switch. The onContainerClick listener will be associated with the main body of the SplitSwitchButton with the onCheckedChange listener associated with the switch area only.
Example of a SplitSwitchButton:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.SplitSwitchButton import androidx.wear.compose.material3.SwitchButton import androidx.wear.compose.material3.Text var checked by remember { mutableStateOf(true) } SplitSwitchButton( label = { Text("Split Switch Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, checked = checked, onCheckedChange = { checked = it }, toggleContentDescription = "Split Switch Button Sample", onContainerClick = { /* Do something */ }, enabled = true, )
For a SplitSwitchButton the background of the tappable background area behind the switch will have a visual effect applied to provide a "divider" between the two tappable areas.
The recommended set of colors can be obtained from SwitchButtonDefaults, e.g. SwitchButtonDefaults.splitSwitchButtonColors.
SplitSwitchButton can be enabled or disabled. A disabled button will not respond to click events.
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this buttons checked status is changed. |
toggleContentDescription: String? |
The content description for the switch control part of the component. |
onContainerClick: () -> Unit |
Click listener called when the user clicks the main body of the button, the area behind the labels. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = SwitchButtonDefaults.splitSwitchButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: SplitSwitchButtonColors = SwitchButtonDefaults.splitSwitchButtonColors() |
|
toggleInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
containerInteractionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
containerClickLabel: String? = null |
Optional click label on the main body of the button for accessibility. |
contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be "start" aligned. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned. |
Stepper
@Composable
fun Stepper(
value: Int,
onValueChange: (Int) -> Unit,
valueProgression: IntProgression,
decreaseIcon: @Composable () -> Unit,
increaseIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: StepperColors = StepperDefaults.colors(),
content: @Composable BoxScope.() -> Unit
): Unit
Stepper allows users to make a selection from a range of values. It's a full-screen control with increase button on the top, decrease button on the bottom and a slot (expected to have either Text or Button) in the middle. Value can be increased and decreased by clicking on the increase and decrease buttons. Buttons can have custom icons - decreaseIcon and increaseIcon. Stepper itself doesn't show the current value but can be displayed via the content slot or StepperLevelIndicator if required. To add range semantics on Stepper, use Modifier.rangeSemantics.
Example of a Stepper with integer values:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableIntStateOf(3) } val valueProgression = remember { 0..10 } Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = { value = it }, valueProgression = valueProgression, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, ) { Text(String.format("Value: %d".format(value))) } StepperLevelIndicator( value = { value }, valueProgression = valueProgression, modifier = Modifier.align(Alignment.CenterStart), ) }
A number of steps is calculated as the difference between max and min values of valueProgression divided by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of steps will be (120-100)/ 5 - 1 = 3. Steps are 100(first), 105, 110, 115, 120(last)
If valueProgression range is not equally divisible by valueProgression.step, then valueProgression.last will be adjusted to the closest divisible value in the range. For example, 1..13 range and a step = 5, steps will be 1(first), 6, 11(last)
If value is not equal to any step value, then it will be coerced to the closest step value. However, the value itself will not be changed and onValueChange in this case will not be triggered.
| Parameters | |
|---|---|
value: Int |
Current value of the Stepper. If outside of |
onValueChange: (Int) -> Unit |
Lambda in which value should be updated. |
valueProgression: IntProgression |
Progression of values that Stepper value can take. Consists of rangeStart, rangeEnd and step. Range will be equally divided by step size. |
decreaseIcon: @Composable () -> Unit |
A slot for an icon which is placed on the decrease (bottom) button. |
increaseIcon: @Composable () -> Unit |
A slot for an icon which is placed on the increase (top) button. |
modifier: Modifier = Modifier |
Modifiers for the Stepper layout. |
enabled: Boolean = true |
Whether the |
colors: StepperColors = StepperDefaults.colors() |
|
content: @Composable BoxScope.() -> Unit |
Content body for the Stepper. |
Stepper
@Composable
fun Stepper(
value: Float,
onValueChange: (Float) -> Unit,
steps: Int,
decreaseIcon: @Composable () -> Unit,
increaseIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat(),
colors: StepperColors = StepperDefaults.colors(),
content: @Composable BoxScope.() -> Unit
): Unit
Stepper allows users to make a selection from a range of values. It's a full-screen control with increase button on the top, decrease button on the bottom and a slot (expected to have either Text or Button) in the middle. Value can be increased and decreased by clicking on the increase and decrease buttons. Buttons can have custom icons - decreaseIcon and increaseIcon. Step value is calculated as the difference between min and max values divided by steps+1. Stepper itself doesn't show the current value but can be displayed via the content slot or StepperLevelIndicator if required. If value is not equal to any step value, then it will be coerced to the closest step value. However, the value itself will not be changed and onValueChange in this case will not be triggered. To add range semantics on Stepper, use Modifier.rangeSemantics.
Example of a simple Stepper with StepperLevelIndicator:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableFloatStateOf(2f) } val valueRange = remember { 0f..4f } Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = { value = it }, valueRange = valueRange, steps = 7, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, ) { Text(String.format("Value: %.1f".format(value))) } StepperLevelIndicator( value = { value }, valueRange = valueRange, modifier = Modifier.align(Alignment.CenterStart), ) }
Example of a Stepper with range semantics:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rangeSemantics import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableFloatStateOf(2f) } val valueRange = remember { 0f..4f } val onValueChange = { i: Float -> value = i } val steps = 7 Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = onValueChange, valueRange = valueRange, modifier = Modifier.rangeSemantics(value, true, onValueChange, valueRange, steps), steps = steps, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, ) { Text("Value: $value") } StepperLevelIndicator( value = { value }, valueRange = valueRange, modifier = Modifier.align(Alignment.CenterStart), ) }
Example of a Stepper with Custom icons and Button content:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.HeadphoneIcon import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableFloatStateOf(2f) } val valueRange = remember { 0f..4f } Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = { value = it }, valueRange = valueRange, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, steps = 7, ) { Text(String.format("Value: %.1f".format(value))) Button( onClick = {}, modifier = Modifier.width(150.dp), label = { Text(text = "This watch", modifier = Modifier.fillMaxWidth()) }, secondaryLabel = { Text(text = "Headphones", modifier = Modifier.fillMaxWidth()) }, icon = { HeadphoneIcon(24.dp) }, ) } StepperLevelIndicator( value = { value }, valueRange = valueRange, modifier = Modifier.align(Alignment.CenterStart), ) }
| Parameters | |
|---|---|
value: Float |
Current value of the Stepper. If outside of |
onValueChange: (Float) -> Unit |
Lambda in which value should be updated. |
steps: Int |
Specifies the number of discrete values, excluding min and max values, evenly distributed across the whole value range. Must not be negative. If 0, stepper will have only min and max values and no steps in between. |
decreaseIcon: @Composable () -> Unit |
A slot for an icon which is placed on the decrease (bottom) button. |
increaseIcon: @Composable () -> Unit |
A slot for an icon which is placed on the increase (top) button. |
modifier: Modifier = Modifier |
Modifiers for the Stepper layout. |
enabled: Boolean = true |
Whether the |
valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat() |
Range of values that Stepper value can take. Passed |
colors: StepperColors = StepperDefaults.colors() |
|
content: @Composable BoxScope.() -> Unit |
Content body for the Stepper. |
StepperLevelIndicator
@Composable
fun StepperLevelIndicator(
value: () -> Float,
modifier: Modifier = Modifier,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
enabled: Boolean = true,
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors(),
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth,
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle,
reverseDirection: Boolean = false
): Unit
Creates a StepperLevelIndicator for screens that that control a setting, such as volume, with a Stepper.
Example of LevelIndicator with a Stepper:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableFloatStateOf(2f) } val valueRange = remember { 0f..4f } Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = { value = it }, valueRange = valueRange, steps = 7, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, ) { Text(String.format("Value: %.1f".format(value))) } StepperLevelIndicator( value = { value }, valueRange = valueRange, modifier = Modifier.align(Alignment.CenterStart), ) }
| Parameters | |
|---|---|
value: () -> Float |
Value of the indicator in the |
modifier: Modifier = Modifier |
Modifier to be applied to the component |
valueRange: ClosedFloatingPointRange<Float> = 0f..1f |
range of values that |
enabled: Boolean = true |
Controls the enabled state of |
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors() |
|
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth |
The stroke width for the indicator and track strokes |
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle |
The angle covered by the curved LevelIndicator, in degrees |
reverseDirection: Boolean = false |
Reverses direction of PositionIndicator if true |
StepperLevelIndicator
@Composable
fun StepperLevelIndicator(
value: () -> Int,
valueProgression: IntProgression,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors(),
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth,
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle,
reverseDirection: Boolean = false
): Unit
Creates a StepperLevelIndicator for screens that that control a setting, such as volume, with a Stepper.
Example of LevelIndicator with a Stepper working on an IntProgression:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Stepper import androidx.wear.compose.material3.StepperDefaults import androidx.wear.compose.material3.StepperLevelIndicator import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.samples.icons.VolumeDownIcon import androidx.wear.compose.material3.samples.icons.VolumeUpIcon var value by remember { mutableIntStateOf(3) } val valueProgression = remember { 0..10 } Box(modifier = Modifier.fillMaxSize()) { Stepper( value = value, onValueChange = { value = it }, valueProgression = valueProgression, decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) }, increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) }, ) { Text(String.format("Value: %d".format(value))) } StepperLevelIndicator( value = { value }, valueProgression = valueProgression, modifier = Modifier.align(Alignment.CenterStart), ) }
| Parameters | |
|---|---|
value: () -> Int |
Current value of the Stepper. If outside of |
valueProgression: IntProgression |
Progression of values that |
modifier: Modifier = Modifier |
Modifier to be applied to the component |
enabled: Boolean = true |
Controls the enabled state of |
colors: LevelIndicatorColors = LevelIndicatorDefaults.colors() |
|
strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth |
The stroke width for the indicator and track strokes |
sweepAngle: @FloatRange(from = 0.0, to = 360.0) Float = LevelIndicatorDefaults.SweepAngle |
The angle covered by the curved LevelIndicator, in degrees |
reverseDirection: Boolean = false |
Reverses direction of PositionIndicator if true |
SuccessConfirmationDialog
@Composable
fun SuccessConfirmationDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.successColors(),
properties: DialogProperties = DialogProperties(),
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis,
content: @Composable () -> Unit = { ConfirmationDialogDefaults.SuccessIcon() }
): Unit
Shows a SuccessConfirmationDialog dialog with a success icon and optional short curved text. This variation of confirmation dialog indicates a successful operation or action.
The confirmation dialog will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, visible parameter should be set to false.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of SuccessConfirmationDialog.
Example of a SuccessConfirmationDialog usage:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.SuccessConfirmationDialog import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } val text = "Success" val style = ConfirmationDialogDefaults.curvedTextStyle SuccessConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText(text, style) }, )
| Parameters | |
|---|---|
visible: Boolean |
A boolean indicating whether the confirmation dialog should be displayed. |
onDismissRequest: () -> Unit |
A lambda function to be called when the dialog is dismissed - either by swiping right or when the |
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.successColors() |
A |
properties: DialogProperties = DialogProperties() |
An optional |
durationMillis: Long = ConfirmationDialogDefaults.DurationMillis |
The duration in milliseconds for which the dialog is displayed. This value will be adjusted by the accessibility manager according to the content displayed. |
content: @Composable () -> Unit = { ConfirmationDialogDefaults.SuccessIcon() } |
A slot for displaying an icon inside the confirmation dialog, which can be animated. Defaults to an animated |
SuccessConfirmationDialogContent
@Composable
fun SuccessConfirmationDialogContent(
curvedText: (CurvedScope.() -> Unit)?,
modifier: Modifier = Modifier,
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.successColors(),
content: @Composable () -> Unit = { ConfirmationDialogDefaults.SuccessIcon() }
): Unit
SuccessConfirmationDialogContent provides the content for a success confirmation dialog with a success icon and optional short curved text. This variation of confirmation dialog indicates a successful operation or action.
Prefer using SuccessConfirmationDialog directly, which provides built-in animations when showing/hiding the dialog. This composable may be used to provide the content for a confirmation dialog if custom show/hide animations are required.
Where user input is required, such as choosing to ok or cancel an action, use AlertDialog instead of SuccessConfirmationDialog.
Example of a SuccessConfirmationDialog usage:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ConfirmationDialog import androidx.wear.compose.material3.ConfirmationDialogDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.SuccessConfirmationDialog import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.confirmationDialogCurvedText var showConfirmation by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { FilledTonalButton( modifier = Modifier.align(Alignment.Center), onClick = { showConfirmation = true }, label = { Text("Show Confirmation") }, ) } val text = "Success" val style = ConfirmationDialogDefaults.curvedTextStyle SuccessConfirmationDialog( visible = showConfirmation, onDismissRequest = { showConfirmation = false }, curvedText = { confirmationDialogCurvedText(text, style) }, )
| Parameters | |
|---|---|
curvedText: (CurvedScope.() -> Unit)? |
A slot for displaying curved text content which will be shown along the bottom edge of the dialog. We recommend using |
modifier: Modifier = Modifier |
Modifier to be applied to the confirmation content. |
colors: ConfirmationDialogColors = ConfirmationDialogDefaults.successColors() |
A |
content: @Composable () -> Unit = { ConfirmationDialogDefaults.SuccessIcon() } |
A slot for displaying an icon inside the confirmation dialog, which can be animated. Defaults to an animated |
SwipeToDismissBox
@Composable
fun SwipeToDismissBox(
state: SwipeToDismissBoxState,
modifier: Modifier = Modifier,
backgroundScrimColor: Color = MaterialTheme.colorScheme.background,
contentScrimColor: Color = MaterialTheme.colorScheme.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
userSwipeEnabled: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit
Wear Material 3 SwipeToDismissBox 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 SwipeToDismissBox 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.fillMaxWidth 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.SwipeToDismissValue import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState import androidx.wear.compose.material3.CheckboxButton import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.SwipeToDismissBox import androidx.wear.compose.material3.Text // 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. SwipeToDismissBox( 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), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically), ) { FilledTonalButton( onClick = { showMainScreen = false }, modifier = Modifier.fillMaxWidth(), ) { Text("Item details") } CheckboxButton( label = { Text("Checkbox", maxLines = 1) }, checked = checked.value, onCheckedChange = { checked.value = it }, modifier = Modifier.fillMaxWidth(), ) } }, ) } else { Column( modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.primary), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text("Show details here...", color = MaterialTheme.colorScheme.onPrimary) Text("Swipe right to dismiss", color = MaterialTheme.colorScheme.onPrimary) } } }
Example of using Modifier.edgeSwipeToDismiss with SwipeToDismissBox:
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.edgeSwipeToDismiss import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.SwipeToDismissBox import androidx.wear.compose.material3.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. SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground -> val horizontalScrollState = rememberScrollState(0) if (isBackground) { Box( modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer) ) } 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.
| Parameters | |
|---|---|
state: SwipeToDismissBoxState |
State containing information about ongoing swipe or animation. |
modifier: Modifier = Modifier |
|
backgroundScrimColor: Color = MaterialTheme.colorScheme.background |
|
contentScrimColor: Color = MaterialTheme.colorScheme.background |
|
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. |
SwipeToDismissBox
@Composable
fun SwipeToDismissBox(
onDismissed: () -> Unit,
modifier: Modifier = Modifier,
state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState(),
backgroundScrimColor: Color = MaterialTheme.colorScheme.background,
contentScrimColor: Color = MaterialTheme.colorScheme.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
userSwipeEnabled: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit
Wear Material 3 SwipeToDismissBox 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.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.SwipeToDismissBox import androidx.wear.compose.material3.Text SwipeToDismissBox(onDismissed = navigateBack) { isBackground -> if (isBackground) { Box( modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer) ) } else { Column( modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.primary), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text("Swipe right to dismiss", color = MaterialTheme.colorScheme.onPrimary) } } }
Example of using Modifier.edgeSwipeToDismiss with SwipeToDismissBox:
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.edgeSwipeToDismiss import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.SwipeToDismissBox import androidx.wear.compose.material3.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. SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground -> val horizontalScrollState = rememberScrollState(0) if (isBackground) { Box( modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer) ) } 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.
| Parameters | |
|---|---|
onDismissed: () -> Unit |
Executes when the swipe to dismiss has completed. |
modifier: Modifier = Modifier |
|
state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState() |
State containing information about ongoing swipe or animation. |
backgroundScrimColor: Color = MaterialTheme.colorScheme.background |
|
contentScrimColor: Color = MaterialTheme.colorScheme.background |
|
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. |
SwipeToReveal
@Composable
fun SwipeToReveal(
primaryAction: @Composable SwipeToRevealScope.() -> Unit,
onSwipePrimaryAction: () -> Unit,
modifier: Modifier = Modifier,
secondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
undoPrimaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
undoSecondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
revealState: RevealState = rememberRevealState(),
revealDirection: RevealDirection = RevealDirection.RightToLeft,
hasPartiallyRevealedState: Boolean = true,
gestureInclusion: GestureInclusion = if (revealDirection == Bidirectional) { bidirectionalGestureInclusion } else { gestureInclusion(revealState) },
content: @Composable () -> Unit
): Unit
SwipeToReveal Material composable. This adds the option to configure up to two additional actions on a Composable: a mandatory primaryAction and an optional secondaryAction. These actions are initially hidden (unless RevealState is created with an initial value other than RevealValue.Covered) and revealed only when the content is swiped - the action buttons can then be clicked. A full swipe of the content triggers the onSwipePrimaryAction callback, which is expected to match the primaryAction's onClick callback. Custom accessibility actions should always be added to the content using Modifier.semantics - examples are shown in the code samples.
Adding undo actions allows users to undo a primary or secondary action that may have been performed inadvertently. The corresponding undo action is displayed when the primary or secondary action is triggered via click or swipe and after SwipeToReveal has animated to the revealed state. After the undo action is clicked, SwipeToReveal animates back to the RevealValue.Covered state and the user can then swipe to reveal if they wish to perform another action.
For destructive actions like "Delete", consider making this the primary action, and providing the undoPrimaryAction.
When using SwipeToReveal with large content items like Cards, it is recommended to set the height of SwipeToRevealScope.PrimaryActionButton and SwipeToRevealScope.SecondaryActionButton to SwipeToRevealDefaults.LargeActionButtonHeight using Modifier.height - in other cases, the Button displayed by SwipeToReveal has height ButtonDefaults.Height by default. It is recommended to always use the default undo button height as created by SwipeToRevealScope.UndoActionButton.
If hasPartiallyRevealedState = true, RevealState should be reset to RevealValue.Covered by the caller when scrolling occurs. This is because the revealed actions are vertically centered on the visible part of the content when the actions are revealed and, if the RevealState is not reset to RevealValue.Covered, actions for tall items would appear off-center when the list is scrolled. See the code samples for examples.
If revealDirection is set to RevealDirection.Bidirectional, the actions revealed on swipe are the same on both sides.
Example of SwipeToReveal with primary and secondary actions and custom accessibility actions:
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.material.icons.outlined.MoreVert import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.SwipeToReveal import androidx.wear.compose.material3.Text SwipeToReveal( primaryAction = { PrimaryActionButton( onClick = { /* This block is called when the primary action is executed. */ }, icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") }, text = { Text("Delete") }, ) }, onSwipePrimaryAction = { /* This block is called when the full swipe gesture is performed. */ }, secondaryAction = { SecondaryActionButton( onClick = { /* This block is called when the secondary action is executed. */ }, icon = { Icon(Icons.Outlined.MoreVert, contentDescription = "Options") }, ) }, undoPrimaryAction = { UndoActionButton( onClick = { /* This block is called when the undo primary action is executed. */ }, text = { Text("Undo Delete") }, ) }, ) { Button( 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 here */ true }, CustomAccessibilityAction("Options") { /* Add the secondary click handler here */ true }, ) }, onClick = {}, ) { Text("This Button has two actions", modifier = Modifier.fillMaxSize()) } }
Example of SwipeToReveal with a Card composable, it reveals a taller button:
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Delete import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.SwipeToReveal import androidx.wear.compose.material3.SwipeToRevealDefaults import androidx.wear.compose.material3.Text SwipeToReveal( primaryAction = { PrimaryActionButton( onClick = { /* This block is called when the primary action is executed. */ }, icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") }, text = { Text("Delete") }, modifier = Modifier.height(SwipeToRevealDefaults.LargeActionButtonHeight), ) }, onSwipePrimaryAction = { /* This block is called when the full swipe gesture is performed. */ }, undoPrimaryAction = { UndoActionButton( onClick = { /* This block is called when the undo primary action is executed. */ }, text = { Text("Undo Delete") }, ) }, ) { Card( modifier = Modifier.fillMaxWidth().semantics { // Use custom actions to make the primary action accessible customActions = listOf( CustomAccessibilityAction("Delete") { /* Add the primary action click handler here */ true } ) }, onClick = {}, ) { Text( "This Card has one action, and the revealed button is taller", modifier = Modifier.fillMaxSize(), ) } }
Example of SwipeToReveal with a TransformingLazyColumn, including resetting the RevealState to RevealValue.Covered when scrolling:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.height import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Delete import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.CompositingStrategy 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.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.items import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RevealValue import androidx.wear.compose.material3.SwipeToReveal import androidx.wear.compose.material3.SwipeToRevealDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight import androidx.wear.compose.material3.rememberRevealState val transformationSpec = rememberTransformationSpec() val tlcState = rememberTransformingLazyColumnState() val coroutineScope = rememberCoroutineScope() val messages = remember { mutableStateListOf<String>().apply { for (i in 1..100) { add("Message #${i}") } } } TransformingLazyColumn( state = tlcState, contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp), modifier = Modifier.background(Color.Black), ) { items(items = messages, key = { it }) { message -> val revealState = rememberRevealState() // SwipeToReveal should be reset to covered when scrolling occurs. LaunchedEffect(tlcState.isScrollInProgress) { if ( tlcState.isScrollInProgress && revealState.currentValue != RevealValue.Covered ) { coroutineScope.launch { revealState.animateTo(targetValue = RevealValue.Covered) } } } SwipeToReveal( primaryAction = { PrimaryActionButton( onClick = { messages.remove(message) }, icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") }, text = { Text("Delete") }, modifier = Modifier.height(SwipeToRevealDefaults.LargeActionButtonHeight), ) }, revealState = revealState, onSwipePrimaryAction = { messages.remove(message) }, modifier = Modifier.transformedHeight(this@items, transformationSpec) .animateItem() .graphicsLayer { with(transformationSpec) { applyContainerTransformation(scrollProgress) } // Is needed to disable clipping. compositingStrategy = CompositingStrategy.ModulateAlpha clip = false }, ) { TitleCard( onClick = {}, title = { Text(message) }, subtitle = { Text("Subtitle") }, modifier = Modifier.semantics { // Use custom actions to make the primary action accessible customActions = listOf( CustomAccessibilityAction("Delete") { messages.remove(message) true } ) }, ) { Text("Message body which extends over multiple lines to extend the card") } } } }
Example of SwipeToReveal with a ScalingLazyColumn, including resetting the RevealState to RevealValue.Covered when scrolling:
import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues 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.material.icons.outlined.MoreVert import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope 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.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.items import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RevealValue import androidx.wear.compose.material3.SwipeToReveal import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.rememberRevealState val slcState = rememberScalingLazyListState() val coroutineScope = rememberCoroutineScope() val messages = remember { mutableStateListOf<String>().apply { for (i in 1..100) { add("This Button $i has two actions") } } } ScalingLazyColumn( state = slcState, contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp), modifier = Modifier.background(Color.Black), ) { items(items = messages, key = { it }) { message -> val revealState = rememberRevealState() // SwipeToReveal should be reset to covered when scrolling occurs. LaunchedEffect(slcState.isScrollInProgress) { if ( slcState.isScrollInProgress && revealState.currentValue != RevealValue.Covered ) { coroutineScope.launch { revealState.animateTo(targetValue = RevealValue.Covered) } } } SwipeToReveal( revealState = revealState, primaryAction = { PrimaryActionButton( onClick = { messages.remove(message) }, icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") }, text = { Text("Delete") }, ) }, onSwipePrimaryAction = { messages.remove(message) }, secondaryAction = { SecondaryActionButton( onClick = { /* This block is called when the secondary action is executed. */ }, icon = { Icon(Icons.Outlined.MoreVert, contentDescription = "Options") }, ) }, ) { Button( modifier = Modifier.fillMaxWidth().semantics { // Use custom actions to make the primary and secondary actions // accessible customActions = listOf( CustomAccessibilityAction("Delete") { messages.remove(message) true }, CustomAccessibilityAction("Options") { /* Add the secondary click handler here */ true }, ) }, onClick = {}, ) { Text(message, modifier = Modifier.fillMaxSize()) } } } }
Example of SwipeToReveal with a ScalingLazyColumn that only executes the primary action when fully swiped (and does not settle after partially revealing the action) by setting hasPartiallyRevealedState = false (so RevealState does not need to be reset when scrolling):
import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues 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.mutableStateListOf import androidx.compose.runtime.remember 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.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.items import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.SwipeToReveal import androidx.wear.compose.material3.Text val slcState = rememberScalingLazyListState() val messages = remember { mutableStateListOf<String>().apply { for (i in 1..100) { add("Message #${i}") } } } ScalingLazyColumn( state = slcState, contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp), modifier = Modifier.background(Color.Black), ) { items(items = messages, key = { it }) { message -> SwipeToReveal( hasPartiallyRevealedState = false, primaryAction = { PrimaryActionButton( onClick = { messages.remove(message) }, icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") }, text = { Text("Delete") }, ) }, onSwipePrimaryAction = { messages.remove(message) }, ) { Button( modifier = Modifier.fillMaxWidth().semantics { // Use custom actions to make the primary action accessible customActions = listOf( CustomAccessibilityAction("Delete") { messages.remove(message) true } ) }, onClick = {}, ) { Text(message, modifier = Modifier.fillMaxSize()) } } } }
| Parameters | |
|---|---|
primaryAction: @Composable SwipeToRevealScope.() -> Unit |
The primary action of this component. |
onSwipePrimaryAction: () -> Unit |
A callback which will be triggered when a full swipe is performed. It is expected that the same callback is given to |
modifier: Modifier = Modifier |
|
secondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null |
Optional secondary action of this component. |
undoPrimaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null |
Optional undo action for the primary action of this component. |
undoSecondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null |
Optional undo action for the secondary action of this component, displayed after |
revealState: RevealState = rememberRevealState() |
|
revealDirection: RevealDirection = RevealDirection.RightToLeft |
The direction from which |
hasPartiallyRevealedState: Boolean = true |
Determines whether the intermediate states |
gestureInclusion: GestureInclusion = if (revealDirection == Bidirectional) {
bidirectionalGestureInclusion
} else {
gestureInclusion(revealState)
} |
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 |
| See also | |
|---|---|
SwipeToReveal |
SwitchButton
@Composable
fun SwitchButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = SwitchButtonDefaults.switchButtonShape,
colors: SwitchButtonColors = SwitchButtonDefaults.switchButtonColors(),
contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
icon: (@Composable BoxScope.() -> Unit)? = null,
secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit
): Unit
The Wear Material SwitchButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start and a column containing the two label slots in the middle.
The SwitchButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SwitchButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.
Example of a SwitchButton:
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.SwitchButton import androidx.wear.compose.material3.Text var checked by remember { mutableStateOf(true) } SwitchButton( label = { Text("Switch Button", maxLines = 3, overflow = TextOverflow.Ellipsis) }, secondaryLabel = { Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis) }, checked = checked, onCheckedChange = { checked = it }, icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") }, enabled = true, )
SwitchButton can be enabled or disabled. A disabled button will not respond to click events.
The recommended set of SwitchButton colors can be obtained from SwitchButtonDefaults, e.g. SwitchButtonDefaults.switchButtonColors.
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this buttons checked status is changed. |
modifier: Modifier = Modifier |
Modifier to be applied to the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shape: Shape = SwitchButtonDefaults.switchButtonShape |
Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme. |
colors: SwitchButtonColors = SwitchButtonDefaults.switchButtonColors() |
|
contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding |
The spacing values to apply internally between the container and the content. |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when button appears inside a container that needs to dynamically change its content separately from the background. |
icon: (@Composable BoxScope.() -> Unit)? = null |
An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be a horizontally and vertically center aligned icon of size 24.dp. |
secondaryLabel: (@Composable RowScope.() -> Unit)? = null |
A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned. |
label: @Composable RowScope.() -> Unit |
A slot for providing the button's main label. The contents are expected to be text which is "start" aligned and no more than 3 lines of text. |
Text
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = LocalTextConfiguration.current.overflow,
softWrap: Boolean = true,
maxLines: Int = LocalTextConfiguration.current.maxLines,
minLines: Int = 1,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
): Unit
High level element that displays text and provides semantics / accessibility information.
The default style uses the LocalTextStyle provided by the MaterialTheme / components. If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override.
For ease of use, commonly used parameters from TextStyle are also present here. The order of precedence is as follows:
-
If a parameter is explicitly set here (i.e, it is not
nullorTextUnit.Unspecified), then this parameter will always be used. -
If a parameter is not set, (
nullorTextUnit.Unspecified), then the corresponding value fromstylewill be used instead.
Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.
| Parameters | |
|---|---|
text: String |
The text to be displayed. |
modifier: Modifier = Modifier |
|
color: Color = Color.Unspecified |
|
fontSize: TextUnit = TextUnit.Unspecified |
The size of glyphs to use when painting the text. See |
fontStyle: FontStyle? = null |
The typeface variant to use when drawing the letters (e.g., italic). See |
fontWeight: FontWeight? = null |
The typeface thickness to use when painting the text (e.g., |
fontFamily: FontFamily? = null |
The font family to be used when rendering the text. See |
letterSpacing: TextUnit = TextUnit.Unspecified |
The amount of space to add between each letter. See |
textDecoration: TextDecoration? = null |
The decorations to paint on the text (e.g., an underline). See |
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign |
The alignment of the text within the lines of the paragraph. See |
lineHeight: TextUnit = TextUnit.Unspecified |
Line height for the |
overflow: TextOverflow = LocalTextConfiguration.current.overflow |
How visual overflow should be handled. |
softWrap: Boolean = true |
Whether the text should break at soft line breaks. If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. If |
maxLines: Int = LocalTextConfiguration.current.maxLines |
An optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to |
minLines: Int = 1 |
The minimum height in terms of minimum number of visible lines. It is required that 1 <= |
onTextLayout: (TextLayoutResult) -> Unit = {} |
Callback that is executed when a new text layout is calculated. A |
style: TextStyle = LocalTextStyle.current |
Style configuration for the text such as color, font, line height etc. |
Text
@Composable
fun Text(
text: AnnotatedString,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = LocalTextConfiguration.current.overflow,
softWrap: Boolean = true,
maxLines: Int = LocalTextConfiguration.current.maxLines,
minLines: Int = 1,
inlineContent: Map<String, InlineTextContent> = mapOf(),
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
): Unit
High level element that displays text and provides semantics / accessibility information.
The default style uses the LocalTextStyle provided by the MaterialTheme / components. If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override.
For ease of use, commonly used parameters from TextStyle are also present here. The order of precedence is as follows:
-
If a parameter is explicitly set here (i.e, it is not
nullorTextUnit.Unspecified), then this parameter will always be used. -
If a parameter is not set, (
nullorTextUnit.Unspecified), then the corresponding value fromstylewill be used instead.
Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.
| Parameters | |
|---|---|
text: AnnotatedString |
The text to be displayed, where |
modifier: Modifier = Modifier |
|
color: Color = Color.Unspecified |
|
fontSize: TextUnit = TextUnit.Unspecified |
The size of glyphs to use when painting the text. See |
fontStyle: FontStyle? = null |
The typeface variant to use when drawing the letters (e.g., italic). See |
fontWeight: FontWeight? = null |
The typeface thickness to use when painting the text (e.g., |
fontFamily: FontFamily? = null |
The font family to be used when rendering the text. See |
letterSpacing: TextUnit = TextUnit.Unspecified |
The amount of space to add between each letter. See |
textDecoration: TextDecoration? = null |
The decorations to paint on the text (e.g., an underline). See |
textAlign: TextAlign? = LocalTextConfiguration.current.textAlign |
The alignment of the text within the lines of the paragraph. See |
lineHeight: TextUnit = TextUnit.Unspecified |
Line height for the |
overflow: TextOverflow = LocalTextConfiguration.current.overflow |
How visual overflow should be handled. |
softWrap: Boolean = true |
Whether the text should break at soft line breaks. If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. If |
maxLines: Int = LocalTextConfiguration.current.maxLines |
An optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to |
minLines: Int = 1 |
The minimum height in terms of minimum number of visible lines. It is required that 1 <= |
inlineContent: Map<String, InlineTextContent> = mapOf() |
A map store composables that replaces certain ranges of the text. It's used to insert composables into text layout. Check |
onTextLayout: (TextLayoutResult) -> Unit = {} |
Callback that is executed when a new text layout is calculated. A |
style: TextStyle = LocalTextStyle.current |
Style configuration for the text such as color, font, line height etc. |
TextButton
@Composable
fun TextButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
enabled: Boolean = true,
shapes: TextButtonShapes = TextButtonDefaults.shapes(),
colors: TextButtonColors = TextButtonDefaults.textButtonColors(),
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material TextButton is a circular, text-only button with transparent background and no border. It offers a single slot for text.
Set the size of the TextButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available. The recommended TextButton sizes are TextButtonDefaults.DefaultButtonSize, TextButtonDefaults.LargeButtonSize and TextButtonDefaults.SmallButtonSize. The recommended text styles for each corresponding button size are TextButtonDefaults.defaultButtonTextStyle, TextButtonDefaults.largeButtonTextStyle and TextButtonDefaults.smallButtonTextStyle.
The default TextButton has no border and a transparent background for low emphasis actions. For actions that require high emphasis, set colors to TextButtonDefaults.filledTextButtonColors. For a medium-emphasis, outlined TextButton, set border to ButtonDefaults.outlinedButtonBorder. For a middle ground between outlined and filled, set colors to TextButtonDefaults.filledTonalTextButtonColors.
TextButton can be enabled or disabled. A disabled button will not respond to click events.
Example of a TextButton:
import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButton TextButton(onClick = { /* Do something */ }) { Text(text = "ABC") }
Example of a large, filled tonal TextButton:
import androidx.compose.foundation.layout.size import androidx.compose.ui.Modifier import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButton import androidx.wear.compose.material3.TextButtonDefaults TextButton( onClick = { /* Do something */ }, colors = TextButtonDefaults.filledTonalTextButtonColors(), modifier = Modifier.size(TextButtonDefaults.LargeButtonSize), ) { Text(text = "ABC", style = TextButtonDefaults.largeButtonTextStyle) }
Example of TextButton with onLongClick:
import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButton TextButton( onClick = { /* Do something for onClick*/ }, onLongClick = onLongClick, onLongClickLabel = "Long click", ) { Text(text = "ABC") }
Example of an TextButton with shape animation of rounded corners on press:
import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButton import androidx.wear.compose.material3.TextButtonDefaults TextButton(onClick = { /* Do something */ }, shapes = TextButtonDefaults.animatedShapes()) { Text(text = "ABC") }
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the button. |
modifier: Modifier = Modifier |
Modifier to be applied to the button. |
onLongClick: (() -> Unit)? = null |
Called when this button is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
enabled: Boolean = true |
Controls the enabled state of the button. When |
shapes: TextButtonShapes = TextButtonDefaults.shapes() |
Defines the shape for this button. Defaults to a static shape based on |
colors: TextButtonColors = TextButtonDefaults.textButtonColors() |
|
border: BorderStroke? = null |
Optional |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
content: @Composable BoxScope.() -> Unit |
The content displayed on the text button, expected to be text or image. |
TextToggleButton
@Composable
fun TextToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: TextToggleButtonColors = TextToggleButtonDefaults.colors(),
interactionSource: MutableInteractionSource? = null,
shapes: TextToggleButtonShapes = TextToggleButtonDefaults.shapes(),
border: BorderStroke? = null,
content: @Composable BoxScope.() -> Unit
): Unit
Wear Material TextToggleButton is a filled text toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for text.
Set the size of the TextToggleButton with Modifier.touchTargetAwareSize to ensure that the background padding will correctly reach the edge of the minimum touch target. The recommended TextToggleButton sizes are TextToggleButtonDefaults.Size, TextToggleButtonDefaults.LargeSize and TextToggleButtonDefaults.ExtraLargeSize. The recommended text styles for each corresponding button size are TextToggleButtonDefaults.textStyle, TextToggleButtonDefaults.largeTextStyle and TextToggleButtonDefaults.extraLargeTextStyle.
TextToggleButton can be enabled or disabled. A disabled button will not respond to click events. When enabled, the checked and unchecked events are propagated by onCheckedChange.
A simple text toggle button using the default colors, animated when pressed.
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextToggleButton import androidx.wear.compose.material3.TextToggleButtonDefaults var checked by remember { mutableStateOf(true) } TextToggleButton( checked = checked, onCheckedChange = { checked = !checked }, shapes = TextToggleButtonDefaults.animatedShapes(), ) { Text(text = if (checked) "On" else "Off") }
A simple text toggle button using the default colors, animated when pressed and with different shapes for the checked and unchecked states.
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextToggleButton import androidx.wear.compose.material3.TextToggleButtonDefaults var checked by remember { mutableStateOf(true) } TextToggleButton( checked = checked, onCheckedChange = { checked = !checked }, shapes = TextToggleButtonDefaults.variantAnimatedShapes(), ) { Text(text = if (checked) "On" else "Off") }
Example of a large text toggle button:
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TextButtonDefaults import androidx.wear.compose.material3.TextToggleButton import androidx.wear.compose.material3.TextToggleButtonDefaults import androidx.wear.compose.material3.touchTargetAwareSize var checked by remember { mutableStateOf(true) } TextToggleButton( checked = checked, onCheckedChange = { checked = !checked }, modifier = Modifier.touchTargetAwareSize(TextButtonDefaults.LargeButtonSize), ) { Text(text = if (checked) "On" else "Off", style = TextToggleButtonDefaults.largeTextStyle) }
| Parameters | |
|---|---|
checked: Boolean |
Boolean flag indicating whether this toggle button is currently checked. |
onCheckedChange: (Boolean) -> Unit |
Callback to be invoked when this toggle button is clicked. |
modifier: Modifier = Modifier |
Modifier to be applied to the toggle button. |
enabled: Boolean = true |
Controls the enabled state of the toggle button. When |
colors: TextToggleButtonColors = TextToggleButtonDefaults.colors() |
|
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
shapes: TextToggleButtonShapes = TextToggleButtonDefaults.shapes() |
Defines the shape for this toggle button. Defaults to a static shape based on |
border: BorderStroke? = null |
Optional |
content: @Composable BoxScope.() -> Unit |
The text to be drawn inside the toggle button. |
TimePicker
@RequiresApi(value = 26)
@Composable
fun TimePicker(
initialTime: LocalTime,
onTimePicked: (LocalTime) -> Unit,
modifier: Modifier = Modifier,
timePickerType: TimePickerType = TimePickerDefaults.timePickerType,
colors: TimePickerColors = TimePickerDefaults.timePickerColors(),
initialSelection: TimePickerSelection = TimePickerDefaults.timePickerSelection(timePickerType)
): Unit
A full screen TimePicker with configurable columns that allows users to select a time.
This component is designed to take most/all of the screen and utilizes large fonts.
Example of a TimePicker:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimePicker var showTimePicker by remember { mutableStateOf(true) } var timePickerTime by remember { mutableStateOf(LocalTime.now()) } if (showTimePicker) { TimePicker( onTimePicked = { timePickerTime = it showTimePicker = false }, initialTime = timePickerTime, // Initialize with last picked time on reopen ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) .withLocale(LocalConfiguration.current.locales[0]) Button( onClick = { showTimePicker = true }, label = { Text("Selected Time") }, secondaryLabel = { Text(timePickerTime.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
Example of a TimePicker with seconds:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimePicker import androidx.wear.compose.material3.TimePickerType var showTimePicker by remember { mutableStateOf(true) } var timePickerTime by remember { mutableStateOf(LocalTime.now()) } if (showTimePicker) { TimePicker( onTimePicked = { timePickerTime = it showTimePicker = false }, timePickerType = TimePickerType.HoursMinutesSeconds24H, initialTime = timePickerTime, // Initialize with last picked time on reopen ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { val formatter = DateTimeFormatter.ofPattern("HH:mm:ss") Button( onClick = { showTimePicker = true }, label = { Text("Selected Time") }, secondaryLabel = { Text(timePickerTime.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
Example of a 12 hour clock TimePicker:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimePicker import androidx.wear.compose.material3.TimePickerType var showTimePicker by remember { mutableStateOf(true) } var timePickerTime by remember { mutableStateOf(LocalTime.now()) } if (showTimePicker) { TimePicker( onTimePicked = { timePickerTime = it showTimePicker = false }, timePickerType = TimePickerType.HoursMinutesAmPm12H, initialTime = timePickerTime, // Initialize with last picked time on reopen ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { val formatter = DateTimeFormatter.ofPattern("hh:mm a") Button( onClick = { showTimePicker = true }, label = { Text("Selected Time") }, secondaryLabel = { Text(timePickerTime.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
Example of a TimePicker with just minutes and seconds:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimePicker import androidx.wear.compose.material3.TimePickerType var showTimePicker by remember { mutableStateOf(true) } var timePickerTime by remember { mutableStateOf(LocalTime.now()) } if (showTimePicker) { TimePicker( onTimePicked = { timePickerTime = it showTimePicker = false }, timePickerType = TimePickerType.MinutesSeconds, initialTime = timePickerTime, // Initialize with last picked time on reopen ) } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { val formatter = DateTimeFormatter.ofPattern("mm:ss") Button( onClick = { showTimePicker = true }, label = { Text("Selected Time") }, secondaryLabel = { Text(timePickerTime.format(formatter)) }, icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") }, ) } }
| Parameters | |
|---|---|
initialTime: LocalTime |
The initial time to be displayed in the TimePicker. |
onTimePicked: (LocalTime) -> Unit |
The callback that is called when the user confirms the time selection. It provides the selected time as |
modifier: Modifier = Modifier |
Modifier to be applied to the |
timePickerType: TimePickerType = TimePickerDefaults.timePickerType |
The different |
colors: TimePickerColors = TimePickerDefaults.timePickerColors() |
|
initialSelection: TimePickerSelection = TimePickerDefaults.timePickerSelection(timePickerType) |
The initial time component to be selected when the |
TimeText
@Composable
fun TimeText(
modifier: Modifier = Modifier,
curvedModifier: CurvedModifier = CurvedModifier,
maxSweepAngle: Float = TimeTextDefaults.MaxSweepAngle,
backgroundColor: Color = TimeTextDefaults.backgroundColor(),
timeSource: TimeSource = TimeTextDefaults.rememberTimeSource(timeFormat()),
contentPadding: PaddingValues = TimeTextDefaults.ContentPadding,
content: CurvedScope.(String) -> Unit = { time -> timeTextCurvedText(time) }
): Unit
Layout to show the current time and a label, they will be drawn in a curve, following the top edge of the screen.
Note that Wear Material UX guidance recommends that time text should not be larger than TimeTextDefaults.MaxSweepAngle of the screen edge, which is enforced by default. It is recommended that additional content, if any, is limited to short status messages before the time using the MaterialTheme.colorScheme.primary color.
For more information, see the Curved Text guide.
A simple TimeText which shows the current time:
import androidx.wear.compose.material3.TimeText // TimeText displays the current time by default. TimeText()
A TimeText with a short app status message shown:
import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.TimeText import androidx.wear.compose.material3.TimeTextDefaults import androidx.wear.compose.material3.timeTextCurvedText import androidx.wear.compose.material3.timeTextSeparator val style = TimeTextDefaults.timeTextStyle() val primaryStyle = TimeTextDefaults.timeTextStyle(color = MaterialTheme.colorScheme.primaryContainer) TimeText { time -> timeTextCurvedText("ETA 12:48", style = primaryStyle) timeTextSeparator(style) timeTextCurvedText(time) }
A TimeText with a long status message, that needs ellipsizing:
import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.foundation.CurvedModifier import androidx.wear.compose.foundation.weight import androidx.wear.compose.material3.TimeText import androidx.wear.compose.material3.TimeTextDefaults import androidx.wear.compose.material3.curvedText import androidx.wear.compose.material3.timeTextCurvedText import androidx.wear.compose.material3.timeTextSeparator val style = TimeTextDefaults.timeTextStyle() TimeText { time -> curvedText( "Long status that should be ellipsized.", CurvedModifier.weight(1f), overflow = TextOverflow.Ellipsis, ) timeTextSeparator(style) timeTextCurvedText(time) }
| Parameters | |
|---|---|
modifier: Modifier = Modifier |
The modifier to be applied to the component. |
curvedModifier: CurvedModifier = CurvedModifier |
The |
maxSweepAngle: Float = TimeTextDefaults.MaxSweepAngle |
The default maximum sweep angle in degrees. |
backgroundColor: Color = TimeTextDefaults.backgroundColor() |
The background color of the arc drawn behind the |
timeSource: TimeSource = TimeTextDefaults.rememberTimeSource(timeFormat()) |
|
contentPadding: PaddingValues = TimeTextDefaults.ContentPadding |
The spacing values between the container and the content. |
content: CurvedScope.(String) -> Unit = { time -> timeTextCurvedText(time) } |
The content of the |
TitleCard
@Composable
fun TitleCard(
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
time: (@Composable () -> Unit)? = null,
subtitle: (@Composable ColumnScope.() -> Unit)? = null,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
transformation: SurfaceTransformation? = null,
content: (@Composable () -> Unit)? = null
): Unit
Opinionated Wear Material 3 Card that offers a specific layout to show interactive information about an application, e.g. a message. TitleCards are designed for use within an application.
This TitleCard does not handle input events - see the other TitleCard overloads if you want a clickable TitleCard.
The time, subtitle and content fields are optional, but it is expected that at least one of these is provided. The layout will vary according to which fields are supplied - see samples.
If the content is text it can be single or multiple line and is expected to be Top and Start aligned. When subtitle is used content shouldn't exceed 2 lines height. Overall the title, content and subtitle text should be no more than 5 rows of text combined.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of a non-clickable TitleCard with time, title and content:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard(title = { Text("Title card") }, time = { Text("Now") }) { Text("Non clickable Card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of text. |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
time: (@Composable () -> Unit)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Depending on whether we have a |
subtitle: (@Composable ColumnScope.() -> Unit)? = null |
An optional slot for displaying the subtitle of the card, expected to be one line of text. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: (@Composable () -> Unit)? = null |
The optional body content of the card. If not provided then title and subtitle are expected to be provided |
TitleCard
@Composable
fun TitleCard(
containerPainter: Painter,
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
time: (@Composable () -> Unit)? = null,
subtitle: (@Composable ColumnScope.() -> Unit)? = null,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding,
transformation: SurfaceTransformation? = null,
content: (@Composable () -> Unit)? = null
): Unit
This TitleCard overload supports an image container background and provides an opinionated Wear Material 3 Card with a specific layout to show interactive information about an application, similar to TitleCard.
This TitleCard does not handle input events - see the other TitleCard overloads if you want a clickable TitleCard.
An image background is a means to reinforce the meaning of information in a Card. Cards should have a content color that contrasts with the background image and scrim. This TitleCard takes containerPainter for the container image background to be drawn (the CardColors containerColor property is ignored). It is recommended to use CardDefaults.containerPainter to create the painter so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The time, subtitle and content fields are optional, but it is expected that at least one of these is provided. The layout will vary according to which fields are supplied - see samples.
If the content is text it can be single or multiple line and is expected to be Top and Start aligned. When subtitle is used content shouldn't exceed 2 lines height. Overall the title, content and subtitle text should be no more than 5 rows of text combined.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of a Card with a background image:
import androidx.compose.foundation.background import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( containerPainter = CardDefaults.containerPainter(image = painterResource(id = R.drawable.backgroundimage)), title = { Text("Card title") }, subtitle = { Text("Subtitle") }, time = { Text("Now") }, contentPadding = CardDefaults.CardWithContainerPainterContentPadding, modifier = Modifier.semantics { contentDescription = "Background image" }, ) { Text("Card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
containerPainter: Painter |
The |
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of text. |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
time: (@Composable () -> Unit)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Depending on whether we have a |
subtitle: (@Composable ColumnScope.() -> Unit)? = null |
An optional slot for displaying the subtitle of the card, expected to be one line of text. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardWithContainerPainterColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding |
The spacing values to apply internally between the container and the content |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: (@Composable () -> Unit)? = null |
The optional body content of the card. If not provided then title and subtitle are expected to be provided |
TitleCard
@Composable
fun TitleCard(
onClick: () -> Unit,
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
time: (@Composable () -> Unit)? = null,
subtitle: (@Composable ColumnScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: (@Composable () -> Unit)? = null
): Unit
Opinionated Wear Material 3 Card that offers a specific layout to show interactive information about an application, e.g. a message. TitleCards are designed for use within an application.
The time, subtitle and content fields are optional, but it is expected that at least one of these is provided. The layout will vary according to which fields are supplied - see samples.
If the content is text it can be single or multiple line and is expected to be Top and Start aligned. When subtitle is used content shouldn't exceed 2 lines height. Overall the title, content and subtitle text should be no more than 5 rows of text combined.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of a TitleCard with onClick, time, title and content:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( onClick = { /* Do something */ }, title = { Text("Title card") }, time = { Text("Now") }, ) { Text("Card content") }
Example of a TitleCard with time, title and subtitle:
import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( onClick = { /* Do something */ }, time = { Text("Now") }, title = { Text("Title card") }, subtitle = { Text("Subtitle") }, )
Example of a TitleCard with images content:
import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( onClick = { /* Do something */ }, title = { Text("Title card") }, time = { Text("Now") }, modifier = Modifier.semantics { contentDescription = "Background image" }, ) { Spacer(Modifier.height(4.dp)) Row(modifier = Modifier.fillMaxWidth()) { Image( modifier = Modifier.weight(2f) .height(68.dp) .align(Alignment.CenterVertically) .clip(RoundedCornerShape(16.dp)), painter = painterResource(id = R.drawable.card_content_image), contentScale = ContentScale.Crop, contentDescription = null, ) Spacer(Modifier.width(4.dp)) Image( modifier = Modifier.weight(1f) .height(68.dp) .align(Alignment.CenterVertically) .clip(RoundedCornerShape(16.dp)), painter = painterResource(id = R.drawable.card_content_image), contentScale = ContentScale.Crop, contentDescription = null, ) } }
Example of an outlined TitleCard:
import androidx.compose.ui.graphics.Color import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( onClick = { /* Do something */ }, title = { Text("Title card") }, time = { Text("Now") }, colors = CardDefaults.outlinedCardColors(), border = CardDefaults.outlinedCardBorder(), ) { Text("Card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of text. |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
time: (@Composable () -> Unit)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Depending on whether we have a |
subtitle: (@Composable ColumnScope.() -> Unit)? = null |
An optional slot for displaying the subtitle of the card, expected to be one line of text. |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.ContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: (@Composable () -> Unit)? = null |
The optional body content of the card. If not provided then title and subtitle are expected to be provided |
TitleCard
@Composable
fun TitleCard(
onClick: () -> Unit,
containerPainter: Painter,
title: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onLongClickLabel: String? = null,
time: (@Composable () -> Unit)? = null,
subtitle: (@Composable ColumnScope.() -> Unit)? = null,
enabled: Boolean = true,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardWithContainerPainterColors(),
border: BorderStroke? = null,
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding,
interactionSource: MutableInteractionSource? = null,
transformation: SurfaceTransformation? = null,
content: (@Composable () -> Unit)? = null
): Unit
This TitleCard overload supports an image container background and provides an opinionated Wear Material 3 Card with a specific layout to show interactive information about an application, similar to TitleCard.
An image background is a means to reinforce the meaning of information in a Card. Cards should have a content color that contrasts with the background image and scrim. This TitleCard takes containerPainter for the container image background to be drawn (the CardColors containerColor property is ignored). It is recommended to use CardDefaults.containerPainter to create the painter so that a scrim is drawn on top of the container image, ensuring that any content above the background is legible.
The time, subtitle and content fields are optional, but it is expected that at least one of these is provided. The layout will vary according to which fields are supplied - see samples.
If the content is text it can be single or multiple line and is expected to be Top and Start aligned. When subtitle is used content shouldn't exceed 2 lines height. Overall the title, content and subtitle text should be no more than 5 rows of text combined.
If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.
Example of a Card with a background image:
import androidx.compose.foundation.background import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.CardDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard TitleCard( onClick = { /* Do something */ }, containerPainter = CardDefaults.containerPainter(image = painterResource(id = R.drawable.backgroundimage)), title = { Text("Card title") }, subtitle = { Text("Subtitle") }, time = { Text("Now") }, contentPadding = CardDefaults.CardWithContainerPainterContentPadding, modifier = Modifier.semantics { contentDescription = "Background image" }, ) { Text("Card content") }
For more information, see the Cards guide.
| Parameters | |
|---|---|
onClick: () -> Unit |
Will be called when the user clicks the card |
containerPainter: Painter |
The |
title: @Composable RowScope.() -> Unit |
A slot for displaying the title of the card, expected to be one or two lines of text. |
modifier: Modifier = Modifier |
Modifier to be applied to the card |
onLongClick: (() -> Unit)? = null |
Called when this card is long clicked (long-pressed). When this callback is set, |
onLongClickLabel: String? = null |
Semantic / accessibility label for the |
time: (@Composable () -> Unit)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Depending on whether we have a |
subtitle: (@Composable ColumnScope.() -> Unit)? = null |
An optional slot for displaying the subtitle of the card, expected to be one line of text. |
enabled: Boolean = true |
Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable. |
shape: Shape = CardDefaults.shape |
Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme |
colors: CardColors = CardDefaults.cardWithContainerPainterColors() |
|
border: BorderStroke? = null |
A BorderStroke object which is used for drawing outlines. |
contentPadding: PaddingValues = CardDefaults.CardWithContainerPainterContentPadding |
The spacing values to apply internally between the container and the content |
interactionSource: MutableInteractionSource? = null |
an optional hoisted |
transformation: SurfaceTransformation? = null |
Transformation to be used when card appears inside a container that needs to dynamically change its content separately from the background. |
content: (@Composable () -> Unit)? = null |
The optional body content of the card. If not provided then title and subtitle are expected to be provided |
VerticalPageIndicator
@Composable
fun VerticalPageIndicator(
pagerState: PagerState,
modifier: Modifier = Modifier,
selectedColor: Color = PageIndicatorDefaults.selectedColor,
unselectedColor: Color = PageIndicatorDefaults.unselectedColor,
backgroundColor: Color = PageIndicatorDefaults.backgroundColor
): Unit
Vertical page indicator for use with VerticalPager, representing the currently active page and the approximate number of pages. Pages are indicated as a Circle shape. The indicator shows up to six pages individually - if there are more than six pages, VerticalPageIndicator shows a smaller indicator to the top and/or bottom to indicate that more pages are available.
To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd, such as by setting modifier = Modifier.align(Alignment.CenterEnd). This way, the VerticalPageIndicator will appear on the right in Ltr orientation and on the left in Rtl orientation. If VerticalPageIndicator is used through VerticalPagerScaffold, then alignment is implicitly set by VerticalPagerScaffold.
Example usage with VerticalPager:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.pager.VerticalPager import androidx.wear.compose.foundation.pager.rememberPagerState import androidx.wear.compose.material3.AnimatedPage import androidx.wear.compose.material3.PagerScaffoldDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.VerticalPageIndicator import androidx.wear.compose.material3.VerticalPagerScaffold val pageCount = 9 val pagerState = rememberPagerState { pageCount } Box { VerticalPagerScaffold( pagerState = pagerState, pageIndicator = { VerticalPageIndicator(pagerState = pagerState) }, ) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior(state = pagerState), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } }
| Parameters | |
|---|---|
pagerState: PagerState |
State of the |
modifier: Modifier = Modifier |
Modifier to be applied to the |
selectedColor: Color = PageIndicatorDefaults.selectedColor |
The color which will be used for a selected indicator item. |
unselectedColor: Color = PageIndicatorDefaults.unselectedColor |
The color which will be used for an unselected indicator item. |
backgroundColor: Color = PageIndicatorDefaults.backgroundColor |
The color which will be used for an indicator background. |
VerticalPagerScaffold
@Composable
fun VerticalPagerScaffold(
pagerState: PagerState,
modifier: Modifier = Modifier,
pageIndicator: (@Composable BoxScope.() -> Unit)? = { VerticalPageIndicator(pagerState) },
pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
content: @Composable () -> Unit
): Unit
VerticalPagerScaffold is one of the Wear Material3 scaffold components.
The scaffold components AppScaffold and VerticalPagerScaffold lay out the structure of a Pager and coordinate transitions of the VerticalPageIndicator and TimeText components.
VerticalPagerScaffold displays the VerticalPageIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and VerticalPageIndicator according to whether the Pager is being paged, this is determined by the PagerState.
VerticalPagerScaffold supports rotary input by default. Rotary input allows users to scroll through the pager's content - by using a crown or a rotating bezel on their Wear OS device. It can be modified or turned off using the rotaryScrollableBehavior parameter.
Example of using AppScaffold and VerticalPagerScaffold with default snap sensitivity, for screens with many pages:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.pager.VerticalPager import androidx.wear.compose.foundation.pager.rememberPagerState import androidx.wear.compose.foundation.rotary.RotaryScrollableDefaults import androidx.wear.compose.material3.AnimatedPage import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.PagerScaffoldDefaults import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.VerticalPagerScaffold AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior(state = pagerState), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(pagerState), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } }
Example of using AppScaffold and VerticalPagerScaffold with PagerSensitivity.Low and RotarySnapSensitivity.Default, for screens where gross motor control is limited:
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.pager.VerticalPager import androidx.wear.compose.foundation.pager.rememberPagerState import androidx.wear.compose.foundation.rotary.RotaryScrollableDefaults import androidx.wear.compose.foundation.rotary.RotarySnapSensitivity import androidx.wear.compose.material3.AnimatedPage import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.PagerScaffoldDefaults import androidx.wear.compose.material3.PagerSensitivity import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.VerticalPagerScaffold AppScaffold { val pagerState = rememberPagerState(pageCount = { 6 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState, sensitivity = PagerSensitivity.Low, ), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior( pagerState = pagerState, snapSensitivity = RotarySnapSensitivity.Default, ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } }
| Parameters | |
|---|---|
pagerState: PagerState |
The state of the pager controlling the page content. |
modifier: Modifier = Modifier |
The modifier to be applied to the scaffold. |
pageIndicator: (@Composable BoxScope.() -> Unit)? = { VerticalPageIndicator(pagerState) } |
A composable function that defines the page indicator to be displayed. By default, it uses a |
pageIndicatorAnimationSpec: AnimationSpec<Float>? = null |
|
content: @Composable () -> Unit |
A composable function where a VerticalPager can be added. |
contentColorFor
@Composable
fun contentColorFor(backgroundColor: Color): Color
The Material color system contains pairs of colors that are typically used for the background and content color inside a component. For example, a Button typically uses primary for its background, and onPrimary for the color of its content (usually text or iconography).
This function tries to match the provided backgroundColor to a 'background' color in this ColorScheme, and then will return the corresponding color used for content. For example, when backgroundColor is ColorScheme.primary, this will return ColorScheme.onPrimary.
If backgroundColor does not match a background color in the theme, this will return the current value of LocalContentColor as a best-effort color.
| Returns | |
|---|---|
Color |
the matching content color for |
| See also | |
|---|---|
contentColorFor |
dynamicColorScheme
fun dynamicColorScheme(context: Context): ColorScheme?
Creates a dynamic color scheme.
Use this function to create a color scheme based on the current watchface. If the user changes the watchface colors, this color scheme will change accordingly. This function checks whether the dynamic color scheme can be used and returns null otherwise. It is expected that callers will check the return value and fallback to their own default color scheme if it is null.
| Parameters | |
|---|---|
context: Context |
The context required to get system resource data. |
rememberAnimatedTextFontRegistry
@Composable
@RequiresApi(value = 31)
fun rememberAnimatedTextFontRegistry(
startFontVariationSettings: FontVariation.Settings,
endFontVariationSettings: FontVariation.Settings,
textStyle: TextStyle = LocalTextStyle.current,
startFontSize: TextUnit = textStyle.fontSize,
endFontSize: TextUnit = textStyle.fontSize
): AnimatedTextFontRegistry
Generates an AnimatedTextFontRegistry to use within composition.
Start and end of the animation is when the animatable is at 0f and 1f, respectively. This API supports overshooting, so a generated font can be extrapolated outside startFontVariationSettings and endFontVariationSettings range, developers need to make sure the given font supports possible font variation settings throughout the animation.
| Parameters | |
|---|---|
startFontVariationSettings: FontVariation.Settings |
Font variation settings at the start of the animation |
endFontVariationSettings: FontVariation.Settings |
Font variation settings at the end of the animation |
textStyle: TextStyle = LocalTextStyle.current |
Text style to be used for the animation |
startFontSize: TextUnit = textStyle.fontSize |
Font size at the start of the animation |
endFontSize: TextUnit = textStyle.fontSize |
Font size at the end of the animation |
rememberPickerState
@Composable
fun rememberPickerState(
initialNumberOfOptions: @IntRange(from = 1) Int,
initiallySelectedIndex: @IntRange(from = 0) Int = 0,
shouldRepeatOptions: Boolean = true
): PickerState
Creates a PickerState that is remembered across compositions.
rememberPlaceholderState
@Composable
fun rememberPlaceholderState(isVisible: Boolean): PlaceholderState
Creates a PlaceholderState that is remembered across compositions.
A PlaceholderState should be created for each component that has placeholder data, such as a Card or a Button. The state is used to coordinate all of the different placeholder effects and animations.
Placeholder has a number of different effects designed to work together. Modifier.placeholderShimmer does a shimmer animation over the whole component that includes the placeholders. There should only be one placeholderShimmer for each component. Modifier.placeholder draws a placeholder shape on top of content that is waiting to load. There can be multiple placeholders in a component. For example, one for the title of an AppCard, another for the app name, and so on.
Once all of the components content is loaded, isVisible is false the shimmer will stop and a wipe off animation will remove the placeholders to reveal the content.
| Parameters | |
|---|---|
isVisible: Boolean |
the initial state of the placeholder. |
rememberRevealState
@Composable
fun rememberRevealState(initialValue: RevealValue = Covered): RevealState
Create and remember a RevealState.
| Parameters | |
|---|---|
initialValue: RevealValue = Covered |
The initial value of the |
ripple
fun ripple(
bounded: Boolean = true,
radius: Dp = Dp.Unspecified,
color: Color = Color.Unspecified
): IndicationNodeFactory
Creates a Ripple using the provided values and values inferred from the theme.
A Ripple is a Material implementation of Indication that expresses different Interactions by drawing ripple animations and state layers.
A Ripple responds to PressInteraction.Press by starting a new ripple animation, and responds to other Interactions by showing a fixed state layer with varying alpha values depending on the Interaction.
MaterialTheme provides Ripples using androidx.compose.foundation.LocalIndication, so a Ripple will be used as the default Indication inside components such as androidx.compose.foundation.clickable and androidx.compose.foundation.indication, in addition to Material provided components that use a Ripple as well.
You can also explicitly create a Ripple and provide it to custom components in order to change the parameters from the default, such as to create an unbounded ripple with a fixed size.
To create a Ripple with a manually defined color that can change over time, see the other ripple overload with a ColorProducer parameter. This will avoid unnecessary recompositions when changing the color, and preserve existing ripple state when the color changes.
| Parameters | |
|---|---|
bounded: Boolean = true |
If true, ripples are clipped by the bounds of the target layout. Unbounded ripples always animate from the target layout center, bounded ripples animate from the touch position. |
radius: Dp = Dp.Unspecified |
the radius for the ripple. If |
color: Color = Color.Unspecified |
the color of the ripple. This color is usually the same color used by the text or iconography in the component. This color will then have alpha applied to calculate the final color used to draw the ripple. If |
ripple
fun ripple(
color: ColorProducer,
bounded: Boolean = true,
radius: Dp = Dp.Unspecified
): IndicationNodeFactory
Creates a Ripple using the provided values and values inferred from the theme.
A Ripple is a Material implementation of Indication that expresses different Interactions by drawing ripple animations and state layers.
A Ripple responds to PressInteraction.Press by starting a new ripple animation, and responds to other Interactions by showing a fixed state layer with varying alpha values depending on the Interaction.
MaterialTheme provides Ripples using androidx.compose.foundation.LocalIndication, so a Ripple will be used as the default Indication inside components such as androidx.compose.foundation.clickable and androidx.compose.foundation.indication, in addition to Material provided components that use a Ripple as well.
You can also explicitly create a Ripple and provide it to custom components in order to change the parameters from the default, such as to create an unbounded ripple with a fixed size.
To create a Ripple with a static color, see the ripple overload with a Color parameter. This overload is optimized for Ripples that have dynamic colors that change over time, to reduce unnecessary recompositions.
| Parameters | |
|---|---|
color: ColorProducer |
the color of the ripple. This color is usually the same color used by the text or iconography in the component. This color will then have alpha applied to calculate the final color used to draw the ripple. If you are creating this |
bounded: Boolean = true |
If true, ripples are clipped by the bounds of the target layout. Unbounded ripples always animate from the target layout center, bounded ripples animate from the touch position. |
radius: Dp = Dp.Unspecified |
the radius for the ripple. If |
Extension functions
SurfaceTransformation
fun TransformingLazyColumnItemScope.SurfaceTransformation(
spec: TransformationSpec
): SurfaceTransformation
Exposes androidx.wear.compose.material3.lazy.TransformationSpec as SurfaceTransformation to be used with Material components.
| Parameters | |
|---|---|
spec: TransformationSpec |
|
confirmationDialogCurvedText
fun CurvedScope.confirmationDialogCurvedText(
text: String,
style: CurvedTextStyle
): Unit
A customized variation of androidx.wear.compose.material3.curvedText that displays text along a curved path. This variation adopts suitable sweep angle and padding for use in ConfirmationDialogs.
| Parameters | |
|---|---|
text: String |
The text to display. |
style: CurvedTextStyle |
It is recommended to use |
contentColorFor
fun ColorScheme.contentColorFor(backgroundColor: Color): Color
The Material color system contains pairs of colors that are typically used for the background and content color inside a component. For example, a Button typically uses primary for its background, and onPrimary for the color of its content (usually text or iconography).
This function tries to match the provided backgroundColor to a 'background' color in this ColorScheme, and then will return the corresponding color used for content. For example, when backgroundColor is ColorScheme.primary, this will return ColorScheme.onPrimary.
If backgroundColor does not match a background color in the theme, this will return Color.Unspecified.
| Returns | |
|---|---|
Color |
the matching content color for |
| See also | |
|---|---|
contentColorFor |
curvedText
fun CurvedScope.curvedText(
text: String,
modifier: CurvedModifier = CurvedModifier,
maxSweepAngle: Float = CurvedTextDefaults.ScrollableContentMaxSweepAngle,
background: Color = Color.Unspecified,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontFamily: FontFamily? = null,
fontWeight: FontWeight? = null,
fontStyle: FontStyle? = null,
fontSynthesis: FontSynthesis? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
letterSpacingCounterClockwise: TextUnit = TextUnit.Unspecified,
style: CurvedTextStyle? = null,
angularDirection: CurvedDirection.Angular? = null,
overflow: TextOverflow = TextOverflow.Clip
): Unit
CurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen). CurvedText can be only created within the CurvedLayout to ensure the best experience, like being able to specify to positioning.
Note that Wear Material UX guidance recommends that curvedText should not exceed the sweep angle CurvedTextDefaults.ScrollableContentMaxSweepAngle on screens with scrollable content such as lists. This limit is enforced by default. For screens without scrollable content, CurvedTextDefaults.StaticContentMaxSweepAngle may be used instead.
The default style uses the LocalTextStyle provided by the MaterialTheme / components, converting it to a CurvedTextStyle. Note that not all parameters are used by curvedText.
If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override, then convert to CurvedTextStyle
For ease of use, commonly used parameters from CurvedTextStyle are also present here. The order of precedence is as follows:
-
If a parameter is explicitly set here (i.e, it is not
nullorTextUnit.Unspecified), then this parameter will always be used. -
If a parameter is not set, (
nullorTextUnit.Unspecified), then the corresponding value fromstylewill be used instead.
Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.
For samples using curved text in a CurvedLayout see:
import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.StrokeCap.Companion.Round import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.CurvedLayout import androidx.wear.compose.foundation.CurvedModifier import androidx.wear.compose.foundation.angularSizeDp import androidx.wear.compose.foundation.background import androidx.wear.compose.foundation.curvedBox import androidx.wear.compose.foundation.curvedRow import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.curvedText val backgroundColor = MaterialTheme.colorScheme.onPrimary val customColor = MaterialTheme.colorScheme.tertiaryDim CurvedLayout { curvedRow(CurvedModifier.background(backgroundColor, Round)) { curvedText("Calling", color = customColor) curvedBox(CurvedModifier.angularSizeDp(5.dp)) {} curvedText("Camilia Garcia") } }
import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Warning import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.StrokeCap.Companion.Round import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.foundation.CurvedDirection import androidx.wear.compose.foundation.CurvedLayout import androidx.wear.compose.foundation.CurvedModifier import androidx.wear.compose.foundation.background import androidx.wear.compose.foundation.curvedComposable import androidx.wear.compose.foundation.curvedRow import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.CurvedTextDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.curvedText val backgroundColor = MaterialTheme.colorScheme.onPrimary CurvedLayout(anchor = 90f, angularDirection = CurvedDirection.Angular.Reversed) { curvedRow(CurvedModifier.background(backgroundColor, Round)) { curvedComposable { Icon( Icons.Filled.Warning, contentDescription = "Warning", modifier = Modifier.size(ButtonDefaults.IconSize), ) } curvedText( "Network lost", maxSweepAngle = CurvedTextDefaults.StaticContentMaxSweepAngle, overflow = TextOverflow.Ellipsis, ) } }
For more information, see the Curved Text guide.
| Parameters | |
|---|---|
text: String |
The text to display |
modifier: CurvedModifier = CurvedModifier |
The |
maxSweepAngle: Float = CurvedTextDefaults.ScrollableContentMaxSweepAngle |
The default maximum sweep angle in degrees. For screens without scrollable content, |
background: Color = Color.Unspecified |
The background color for the text. |
color: Color = Color.Unspecified |
|
fontSize: TextUnit = TextUnit.Unspecified |
The size of glyphs to use when painting the text. See |
fontFamily: FontFamily? = null |
The font family to be used when rendering the text. |
fontWeight: FontWeight? = null |
The thickness of the glyphs, in a range of 1, 1000. see |
fontStyle: FontStyle? = null |
The typeface variant to use when drawing the letters (e.g. italic). |
fontSynthesis: FontSynthesis? = null |
Whether to synthesize font weight and/or style when the requested weight or style cannot be found in the provided font family. |
letterSpacing: TextUnit = TextUnit.Unspecified |
The amount of space (in em or sp) to add between each letter, when text is going clockwise. |
letterSpacingCounterClockwise: TextUnit = TextUnit.Unspecified |
The amount of space (in em or sp) to add between each letter, when text is going counterClockwise. Note that this usually needs to be bigger than |
style: CurvedTextStyle? = null |
Specifies the style to use. |
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. |
drawCircularProgressIndicator
fun DrawScope.drawCircularProgressIndicator(
progress: Float,
colors: ProgressIndicatorColors,
strokeWidth: Dp,
enabled: Boolean = true,
allowProgressOverflow: Boolean = false,
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
endAngle: Float = startAngle,
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit
Draw a simple non-animating circular progress indicator. Prefer to use CircularProgressIndicator directly instead of this method in order to access the recommended animations, but this method can be used when custom animations are required.
Example of a circular progress indicator with custom progress animation:
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.CircularProgressIndicator import androidx.wear.compose.material3.CircularProgressIndicatorDefaults import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ProgressIndicatorDefaults import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.drawCircularProgressIndicator val progress = remember { mutableFloatStateOf(0f) } val animatedProgress = remember { Animatable(0f) } val colors = ProgressIndicatorDefaults.colors(indicatorColor = Color.Green, trackColor = Color.White) LaunchedEffect(Unit) { snapshotFlow(progress::value).collectLatest { animatedProgress.animateTo(it, tween(durationMillis = 1024, easing = LinearEasing)) } } Box( modifier = Modifier.background(MaterialTheme.colorScheme.background) .padding(CircularProgressIndicatorDefaults.FullScreenPadding) .fillMaxSize() ) { Button( modifier = Modifier.align(Alignment.Center).padding(12.dp), onClick = { progress.floatValue = if (progress.floatValue == 0f) 1f else 0f }, label = { Text("Animate") }, ) // Draw the circular progress indicator with custom animation Spacer( Modifier.fillMaxSize().focusable().drawBehind { drawCircularProgressIndicator( progress = animatedProgress.value, strokeWidth = 10.dp, colors = colors, startAngle = 120f, endAngle = 60f, ) } ) }
| Parameters | |
|---|---|
progress: Float |
The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. |
colors: ProgressIndicatorColors |
|
strokeWidth: Dp |
The stroke width for the progress indicator. The recommended values are |
enabled: Boolean = true |
controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is |
allowProgressOverflow: Boolean = false |
When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color |
startAngle: Float = CircularProgressIndicatorDefaults.StartAngle |
The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees |
endAngle: Float = startAngle |
The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to |
gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth) |
The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance. |
minimumInteractiveComponentSize
fun Modifier.minimumInteractiveComponentSize(): Modifier
Reserves at least 48.dp in size to disambiguate touch interactions if the element would measure smaller.
https://m3.material.io/foundations/accessible-design/accessibility-basics#28032e45-c598-450c-b355-f9fe737b1cd8
This uses the Material recommended minimum size of 48.dp x 48.dp, which may not the same as the system enforced minimum size.
This modifier is not needed for touch target expansion to happen. It only affects layout, to make sure there is adequate space for touch target expansion.
openOnPhoneDialogCurvedText
fun CurvedScope.openOnPhoneDialogCurvedText(
text: String,
style: CurvedTextStyle
): Unit
A customized variation of androidx.wear.compose.material3.curvedText that displays text along a curved path. This variation adopts suitable sweep angle and padding for use in OpenOnPhoneDialog.
| Parameters | |
|---|---|
text: String |
The text to display. |
style: CurvedTextStyle |
The style to apply to the text. It is recommended to use |
placeholder
@Composable
fun Modifier.placeholder(
placeholderState: PlaceholderState,
shape: Shape = PlaceholderDefaults.shape,
color: Color = PlaceholderDefaults.color
): Modifier
Modifier.placeholder draws a skeleton shape over a component, for situations when no provisional content (such as cached data) is available. The placeholder skeleton can be displayed instead, while the content is loading. The reveal of the content will be animated when it becomes available (and hidden again if the content becomes unavailable), unless the ReducedMotion setting is enabled, in which case those are instantaneous. NOTE: For animations to work, an AppScaffold should be used.
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.placeholder import androidx.wear.compose.material3.placeholderShimmer import androidx.wear.compose.material3.rememberPlaceholderState var labelText by remember { mutableStateOf("") } var imageVector: ImageVector? by remember { mutableStateOf(null) } val buttonPlaceholderState = rememberPlaceholderState(isVisible = labelText.isEmpty() || imageVector == null) FilledTonalButton( onClick = { /* Do something */ }, enabled = true, modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState), label = { Text( text = labelText, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.fillMaxWidth().placeholder(buttonPlaceholderState), ) }, icon = { Box( modifier = Modifier.size(ButtonDefaults.IconSize).placeholder(buttonPlaceholderState) ) { if (imageVector != null) { Icon( imageVector = imageVector!!, contentDescription = "Heart", modifier = Modifier.wrapContentSize(align = Alignment.Center) .size(ButtonDefaults.IconSize) .fillMaxSize(), ) } } }, ) // Simulate content loading completing in stages LaunchedEffect(Unit) { delay(2000) imageVector = Icons.Filled.Favorite delay(1000) labelText = "A label" }
If there is some cached data for this field, it may be better to show that while loading, see
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.placeholder import androidx.wear.compose.material3.placeholderShimmer import androidx.wear.compose.material3.rememberPlaceholderState var labelText by remember { mutableStateOf("Cached Data") } var imageVector: ImageVector? by remember { mutableStateOf(null) } val buttonPlaceholderState = rememberPlaceholderState(isVisible = labelText.isEmpty() || imageVector == null) // Put placeholderShimmer in the container and placeholder in the elements of the content that // have no cached data. FilledTonalButton( onClick = { /* Do something */ }, enabled = true, modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState), label = { Text( text = labelText, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.fillMaxWidth(), ) }, icon = { Box( modifier = Modifier.size(ButtonDefaults.IconSize).placeholder(buttonPlaceholderState) ) { if (imageVector != null) { Icon( imageVector = imageVector!!, contentDescription = "Heart", modifier = Modifier.wrapContentSize(align = Alignment.Center) .size(ButtonDefaults.IconSize) .fillMaxSize(), ) } } }, ) // Simulate content loading completing in stages LaunchedEffect(Unit) { delay(2000) imageVector = Icons.Filled.Favorite delay(1000) labelText = "A label" }
Note that the component should still be sized close to the target, so the final reveal of the content is less disruptive.
| Parameters | |
|---|---|
placeholderState: PlaceholderState |
the state used to coordinate several placeholder effects. |
shape: Shape = PlaceholderDefaults.shape |
the shape of the placeholder. |
color: Color = PlaceholderDefaults.color |
the color to use in the placeholder. |
placeholderShimmer
@Composable
fun Modifier.placeholderShimmer(
placeholderState: PlaceholderState,
shape: Shape = PlaceholderDefaults.shape,
color: Color = PlaceholderDefaults.shimmerColor
): Modifier
Modifier.placeholderShimmer draws a periodic shimmer over content, indicating to the user that contents are loading or potentially out of date. The placeholder shimmer is a 45 degree gradient from Top|Left of the screen to Bottom|Right. The shimmer is coordinated via the animation frame clock which orchestrates the shimmer so that every component will shimmer as the gradient progresses across the screen. NOTE: For animations to work, an AppScaffold should be used.
Example of a Button with icon and a label that put placeholders over individual content slots and then draws a placeholder shimmer over the result:
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.placeholder import androidx.wear.compose.material3.placeholderShimmer import androidx.wear.compose.material3.rememberPlaceholderState var labelText by remember { mutableStateOf("") } var imageVector: ImageVector? by remember { mutableStateOf(null) } val buttonPlaceholderState = rememberPlaceholderState(isVisible = labelText.isEmpty() || imageVector == null) FilledTonalButton( onClick = { /* Do something */ }, enabled = true, modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState), label = { Text( text = labelText, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.fillMaxWidth().placeholder(buttonPlaceholderState), ) }, icon = { Box( modifier = Modifier.size(ButtonDefaults.IconSize).placeholder(buttonPlaceholderState) ) { if (imageVector != null) { Icon( imageVector = imageVector!!, contentDescription = "Heart", modifier = Modifier.wrapContentSize(align = Alignment.Center) .size(ButtonDefaults.IconSize) .fillMaxSize(), ) } } }, ) // Simulate content loading completing in stages LaunchedEffect(Unit) { delay(2000) imageVector = Icons.Filled.Favorite delay(1000) labelText = "A label" }
Example of a simple text placeholder:
import androidx.compose.foundation.layout.width import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.placeholder import androidx.wear.compose.material3.placeholderShimmer import androidx.wear.compose.material3.rememberPlaceholderState var labelText by remember { mutableStateOf("") } val placeholderState = rememberPlaceholderState(isVisible = labelText.isEmpty()) Text( text = labelText, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center, modifier = Modifier.width(90.dp).placeholderShimmer(placeholderState).placeholder(placeholderState), ) // Simulate content loading LaunchedEffect(Unit) { delay(3000) labelText = "A label" }
| Parameters | |
|---|---|
placeholderState: PlaceholderState |
the current placeholder state that determine whether the placeholder shimmer should be shown. |
shape: Shape = PlaceholderDefaults.shape |
the shape of the component. |
color: Color = PlaceholderDefaults.shimmerColor |
the color to use in the shimmer. |
rangeSemantics
fun Modifier.rangeSemantics(
value: Float,
enabled: Boolean,
onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float>,
steps: Int
): Modifier
Modifier to add semantics signifying progress of the Stepper/Slider.
| Parameters | |
|---|---|
value: Float |
Current value of the ProgressIndicator/Slider. If outside of |
enabled: Boolean |
If false then semantics will not be added. |
onValueChange: (Float) -> Unit |
Lambda which updates |
valueRange: ClosedFloatingPointRange<Float> |
Range of values that value can take. Passed |
steps: Int |
If greater than 0, specifies the amounts of discrete values, evenly distributed between across the whole value range. If 0, any value from the range specified is allowed. Must not be negative. |
scrollAway
fun Modifier.scrollAway(
scrollInfoProvider: ScrollInfoProvider,
screenStage: () -> ScreenStage
): Modifier
Scroll an item vertically in/out of view based on scroll state provided by a scrolling list. Typically used to scroll a TimeText item out of view as the user starts to scroll a vertically scrollable list of items upwards and bring additional items into view.
Example of using ScrollAway directly (in practice, it is recommended to use AppScaffold and ScreenScaffold to provide the correct scroll away behavior by default):
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.ScrollInfoProvider import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.FilledTonalButton import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.ScreenStage import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimeText import androidx.wear.compose.material3.curvedText import androidx.wear.compose.material3.scrollAway import androidx.wear.compose.material3.timeTextSeparator val state = rememberScalingLazyListState() Box(modifier = Modifier.fillMaxSize()) { ScalingLazyColumn(state = state, modifier = Modifier.fillMaxSize()) { item { ListHeader { Text( modifier = Modifier.fillMaxWidth(), text = "ScalingLazyColumn", textAlign = TextAlign.Center, ) } } items(50) { FilledTonalButton( modifier = Modifier.fillMaxWidth().padding(horizontal = 36.dp), onClick = {}, label = { Text("Item ${it + 1}") }, ) } } TimeText( // In practice, it is recommended to use the [AppScaffold] and [ScreenScaffold], // so that the Material3 scroll away behavior is provided by default, rather than using // [Modifier.scrollAway] directly. modifier = Modifier.scrollAway( scrollInfoProvider = ScrollInfoProvider(state), screenStage = { if (state.isScrollInProgress) ScreenStage.Scrolling else ScreenStage.Idle }, ), content = { time -> curvedText("ScrollAway") timeTextSeparator() curvedText(time) }, ) }
| Parameters | |
|---|---|
scrollInfoProvider: ScrollInfoProvider |
Used as the basis for the scroll-away implementation, based on the state of the scrollable container. See |
screenStage: () -> ScreenStage |
Function that returns the screen stage of the active screen. Scrolled away items are shown when the screen is new, then scrolled away or hidden when scrolling, and finally shown again when idle. |
timeTextCurvedText
fun CurvedScope.timeTextCurvedText(time: String, style: CurvedTextStyle? = null): Unit
Default curved text to use in a TimeText, for displaying the time
| Parameters | |
|---|---|
time: String |
The time to display. |
style: CurvedTextStyle? = null |
A |
timeTextSeparator
fun CurvedScope.timeTextSeparator(
curvedTextStyle: CurvedTextStyle? = null,
contentArcPadding: ArcPaddingValues = ArcPaddingValues(angular = 4.dp)
): Unit
A default implementation of Separator, to be shown between any text/composable and the time.
| Parameters | |
|---|---|
curvedTextStyle: CurvedTextStyle? = null |
A |
contentArcPadding: ArcPaddingValues = ArcPaddingValues(angular = 4.dp) |
|
touchTargetAwareSize
fun Modifier.touchTargetAwareSize(size: Dp): Modifier
Modifier to set both the size and recommended touch target for IconButton and TextButton.
Top-level properties
LocalContentColor
val LocalContentColor: ProvidableCompositionLocal<Color>
CompositionLocal containing the preferred content color for a given position in the hierarchy. This typically represents the on color for a color in ColorScheme. For example, if the background color is ColorScheme.surfaceContainer, this color is typically set to ColorScheme.onSurface.
This color should be used for any typography / iconography, to ensure that the color of these adjusts when the background color changes. For example, on a dark background, text should be light, and on a light background, text should be dark.
Defaults to Color.White if no color has been explicitly set.
LocalTextConfiguration
val LocalTextConfiguration: ProvidableCompositionLocal<TextConfiguration>
CompositionLocal containing the preferred TextConfiguration that will be used by Text components by default consisting of text alignment, overflow specification and max lines. Material3 components related to text such as Button, CheckboxButton, SwitchButton, RadioButton use LocalTextConfiguration to set values with which to style child text components.
LocalTextStyle
val LocalTextStyle: ProvidableCompositionLocal<TextStyle>
CompositionLocal containing the preferred TextStyle that will be used by Text components by default. To set the value for this CompositionLocal, see ProvideTextStyle which will merge any missing TextStyle properties with the existing TextStyle set in this CompositionLocal.
| See also | |
|---|---|
ProvideTextStyle |