androidx.wear.protolayout.material3
Classes
AppCardStyle |
Provides style values for the app card component. |
AvatarButtonStyle |
Provides style values for the avatar button component. |
ButtonColors |
Represents the container and content colors used in buttons, such as |
ButtonGroupScope |
Scope for the children of a |
ButtonStyle |
Provides style values for the pill shape button component. |
CardColors |
Represents colors used in card components, such as |
ColorScheme |
A |
DataCardStyle |
Provides style values for the data card component. |
GraphicDataCardStyle |
Provides style values for the graphic data card component. |
IconButtonStyle |
Provides style values for the icon button component. |
MaterialScope |
Receiver scope which is used by all ProtoLayout Material3 components and layout to support opinionated defaults and to provide the global information for styling Material3 components. |
PrimaryLayoutMargins |
The set of margins for the |
ProgressIndicatorColors |
Represents the indicator and track colors used in progress indicator. |
Shapes |
Material surfaces can be displayed in different shapes. |
TextButtonStyle |
Provides style values for the text button component. |
TitleCardStyle |
Provides style values for the title card component. |
TitleContentPlacementInDataCard |
Defines the placement of the |
Objects
ButtonDefaults |
|
ButtonGroupDefaults |
Contains the default values used by |
CardDefaults |
|
CircularProgressIndicatorDefaults |
|
GraphicDataCardDefaults |
|
TitleCardDefaults |
|
Typography |
Class holding typography definitions as defined by the Wear Material3 typography specification. |
Annotations
MaterialScopeMarker |
DSL marker used to distinguish between |
Top-level functions summary
ColorScheme |
dynamicColorScheme(context: Context, defaultColorScheme: ColorScheme)Creates a dynamic color scheme. |
Boolean |
isDynamicColorSchemeEnabled(context: Context)Returns whether the dynamic colors scheme (colors following the current system theme) is enabled. |
LayoutElementBuilders.LayoutElement |
materialScope(Creates a top-level receiver scope |
LayoutElementBuilders.LayoutElement |
materialScopeWithResources(Creates a top-level receiver scope |
Extension functions summary
Top-level functions
dynamicColorScheme
fun dynamicColorScheme(
context: Context,
defaultColorScheme: ColorScheme = ColorScheme()
): ColorScheme
Creates a dynamic color scheme.
Use this function to create a color scheme based on the current system theme. If the user changes the system theme, this color scheme will change accordingly. This function checks whether the dynamic color scheme can be used and returns defaultColorScheme otherwise.
| Parameters | |
|---|---|
context: Context |
The context required to get system resource data. |
defaultColorScheme: ColorScheme = ColorScheme() |
The fallback |
isDynamicColorSchemeEnabled
fun isDynamicColorSchemeEnabled(context: Context): Boolean
Returns whether the dynamic colors scheme (colors following the current system theme) is enabled.
If enabled, and elements or MaterialScope are opted in to using dynamic theme, colors will change whenever system theme changes.
materialScope
fun materialScope(
context: Context,
deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
allowDynamicTheme: Boolean = true,
defaultColorScheme: ColorScheme = ColorScheme(),
layout: MaterialScope.() -> LayoutElementBuilders.LayoutElement
): LayoutElementBuilders.LayoutElement
Creates a top-level receiver scope MaterialScope that calls the given layout to support for opinionated defaults and building Material3 components and layout, with default dynamic theme colors defined in dynamicColorScheme.
The colors of elements in this receiver scope will automatically follow colors from the system theme, including whenever user changes the theme. If dynamic color scheme is switched off by user or unavailable on device, defaults to static, default ColorScheme.
| Parameters | |
|---|---|
context: Context |
The Android Context for the Tile service |
deviceConfiguration: DeviceParametersBuilders.DeviceParameters |
The device parameters for where the components will be rendered |
allowDynamicTheme: Boolean = true |
Whether dynamic colors theme should be used on components, meaning that colors will follow the system theme if enabled on the device. If not set, defaults to using the system theme |
defaultColorScheme: ColorScheme = ColorScheme() |
Color Scheme with static colors. The color theme to be used, when |
layout: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
Scoped slot for the content of layout to be displayed |
materialScopeWithResources
fun materialScopeWithResources(
context: Context,
protoLayoutScope: ProtoLayoutScope,
deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
allowDynamicTheme: Boolean = true,
defaultColorScheme: ColorScheme = ColorScheme(),
layout: MaterialScope.() -> LayoutElementBuilders.LayoutElement
): LayoutElementBuilders.LayoutElement
Creates a top-level receiver scope MaterialScope that calls the given layout to support for opinionated defaults and building Material3 components and layout, with default dynamic theme colors defined in dynamicColorScheme and automatic resource registration for Image elements created with ProtoLayoutScope.
The colors of elements in this receiver scope will automatically follow colors from the system theme, including whenever user changes the theme. If dynamic color scheme is switched off by user or unavailable on device, defaults to static, default ColorScheme.
| Parameters | |
|---|---|
context: Context |
The Android Context for the Tile service |
protoLayoutScope: ProtoLayoutScope |
The |
deviceConfiguration: DeviceParametersBuilders.DeviceParameters |
The device parameters for where the components will be rendered |
allowDynamicTheme: Boolean = true |
Whether dynamic colors theme should be used on components, meaning that colors will follow the system theme if enabled on the device. If not set, defaults to using the system theme |
defaultColorScheme: ColorScheme = ColorScheme() |
Color Scheme with static colors. The color theme to be used, when |
layout: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
Scoped slot for the content of layout to be displayed |
Extension functions
appCard
fun MaterialScope.appCard(
onClick: ModifiersBuilders.Clickable,
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
avatar: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
label: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = if (deviceConfiguration.screenWidthDp.isBreakpoint()) { shapes.extraLarge } else { shapes.large },
colors: CardColors = filledCardColors(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
style: AppCardStyle = defaultAppCardStyle(),
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 app card that offers up to 5 slots, usually text based.
Those are vertically stacked title and content, and additional side slot for a time.
The first row of the card has three slots:
-
a small optional image, such as
avatarImage -
label, which is expected to be a short
text -
time, end aligned.
The second row shows a title, this is expected to be a single row of start aligned text.
The rest of the appCard contains the content which should be text.
The card's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.AppCardStyle import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors import androidx.wear.protolayout.material3.appCard import androidx.wear.protolayout.material3.card import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { appCard( onClick = clickable, modifier = LayoutModifier.contentDescription("App Card"), height = expand(), colors = filledTonalCardColors(), style = AppCardStyle.largeAppCardStyle(), title = { text("This is title of the app card".layoutString) }, time = { text("NOW".layoutString) }, label = { text("Label".layoutString) }, content = { text("Content of the Card!".layoutString) }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying the title of the card, expected to be one line of text. Uses |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The optional body content of the card. Uses |
avatar: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot in header for displaying small image, such as |
label: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot in header for displaying short, label text. Uses |
time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Uses |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this card. It's highly recommended to leave this with default value as |
shape: ModifiersBuilders.Corner = if (deviceConfiguration.screenWidthDp.isBreakpoint()) {
shapes.extraLarge
} else {
shapes.large
} |
Defines the card's shape, in other words the corner radius for this card. If changing these to radius smaller than |
colors: CardColors = filledCardColors() |
The colors to be used for a background and inner content of this card. If the background image is also specified, the image will be laid out on top of the background color. In case of the fully opaque background image, then the background color will not be shown. Specified colors can be |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the card. It is recommended to use the default styling that is automatically provided by only calling |
style: AppCardStyle = defaultAppCardStyle() |
The style which provides the attribute values required for constructing this title card and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
avatarButton
fun MaterialScope.avatarButton(
onClick: ModifiersBuilders.Clickable,
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
avatarContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: ButtonColors = filledButtonColors(),
style: AvatarButtonStyle = defaultAvatarButtonStyle(),
horizontalAlignment: Int = HORIZONTAL_ALIGN_START,
contentPadding: ModifiersBuilders.Padding = style.innerVerticalPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 pill shape avatar button that offers up to three slots to take content representing vertically stacked label and secondary label, and an image (avatar) next to it.
Difference from the button is that this one takes an image instead of an icon and spaces the content proportionally, so that edge of the button nicely hugs the avatar image.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.material3.avatarButton import androidx.wear.protolayout.material3.avatarImage import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString avatarButton( onClick = clickable(), modifier = LayoutModifier.contentDescription("Pill button"), avatarContent = { avatarImage("id") }, labelContent = { text("Primary label".layoutString) }, secondaryLabelContent = { text("Secondary label".layoutString) }, )
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
avatarContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The avatar slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this button. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the button's shape, in other words the corner radius for this button. If changing these to radius smaller than |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
style: AvatarButtonStyle = defaultAvatarButtonStyle() |
The style which provides the attribute values required for constructing this pill shape button and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
horizontalAlignment: Int = HORIZONTAL_ALIGN_START |
The horizontal placement of the |
contentPadding: ModifiersBuilders.Padding = style.innerVerticalPadding |
The inner padding used to prevent inner content from being too close to the button's edge. It's highly recommended to keep the default. Only vertical values would be used, as horizontally elements are spaced out proportionally to the buttons width. |
avatarImage
fun MaterialScope.avatarImage(
protoLayoutResourceId: String,
width: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.width,
height: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.height,
modifier: LayoutModifier = LayoutModifier,
contentScaleMode: Int = defaultAvatarImageStyle.contentScaleMode
): LayoutElementBuilders.LayoutElement
Returns the avatar image with the defined style.
Material components such as appCard provide proper defaults for the small avatar image. In order to take advantage of those defaults, this should be used with the resource ID only: avatarImage("id").
| Parameters | |
|---|---|
protoLayoutResourceId: String |
The protolayout resource id of the image. Node that, this is not an Android resource id. |
width: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.width |
The width of an image. Usually, a small image that fit into the component's slot. |
height: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.height |
The height of an image. Usually, a small image that fit into the component's slot. |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. |
contentScaleMode: Int = defaultAvatarImageStyle.contentScaleMode |
The content scale mode for the image to define how image will adapt to the given size |
avatarImage
fun MaterialScope.avatarImage(
resource: ResourceBuilders.ImageResource,
protoLayoutResourceId: String? = null,
width: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.width,
height: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.height,
modifier: LayoutModifier = LayoutModifier,
contentScaleMode: Int = defaultAvatarImageStyle.contentScaleMode
): LayoutElementBuilders.LayoutElement
Returns the avatar image with the defined style which will be automatically registered as a resource.
Material components such as appCard provide proper defaults for the small avatar image. In order to take advantage of those defaults, this should be used with the resource ID only: avatarImage(imageResource).
Note that, by using this method, there's no need to register resource for Tiles in androidx.wear.tiles.TileService.onTileResourcesRequest.
| Parameters | |
|---|---|
resource: ResourceBuilders.ImageResource |
An Image resource, used in the layout in the place of this element. |
protoLayoutResourceId: String? = null |
The optional protolayout resource id of the icon. |
width: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.width |
The width of an image. Usually, a small image that fit into the component's slot. |
height: DimensionBuilders.ImageDimension = defaultAvatarImageStyle.height |
The height of an image. Usually, a small image that fit into the component's slot. |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. |
contentScaleMode: Int = defaultAvatarImageStyle.contentScaleMode |
The content scale mode for the image to define how image will adapt to the given size @throws IllegalStateException if this method is called without |
backgroundImage
fun MaterialScope.backgroundImage(
protoLayoutResourceId: String,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.width,
height: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.height,
overlayColor: LayoutColor? = defaultBackgroundImageStyle.overlayColor,
contentScaleMode: Int = defaultBackgroundImageStyle.contentScaleMode
): LayoutElementBuilders.LayoutElement
Returns the image background with the defined style.
Material components provide proper defaults for the background image. In order to take advantage of those defaults, this should be used with the resource ID only: backgroundImage("id").
This image can have optional overlay on top of it, that is usually a dark color with opacity. This is highly recommended to be added when there's additional content like text on top of image, to improve readability.
If this is used in imageButton as image button with no other content, overlayColor can be omitted, and the overlay color on top of the image would be ignored.
| Parameters | |
|---|---|
protoLayoutResourceId: String |
The protolayout resource id of the image. Node that, this is not an Android resource id. |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. |
width: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.width |
The width of an image. Usually, this matches the width of the parent component this is used in. |
height: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.height |
The height of an image. Usually, this matches the height of the parent component this is used in. |
overlayColor: LayoutColor? = defaultBackgroundImageStyle.overlayColor |
The color used to provide the overlay over the image for better readability. It's recommended to use |
contentScaleMode: Int = defaultBackgroundImageStyle.contentScaleMode |
The content scale mode for the image to define how image will adapt to the given size |
backgroundImage
fun MaterialScope.backgroundImage(
resource: ResourceBuilders.ImageResource,
protoLayoutResourceId: String? = null,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.width,
height: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.height,
overlayColor: LayoutColor? = defaultBackgroundImageStyle.overlayColor,
contentScaleMode: Int = defaultBackgroundImageStyle.contentScaleMode
): LayoutElementBuilders.LayoutElement
Returns the image background with the defined style which will be automatically registered as a resource.
Material components provide proper defaults for the background image. In order to take advantage of those defaults, this should be used with the resource ID only: backgroundImage(imageResource).
Note that, by using this method, there's no need to register resource for Tiles in androidx.wear.tiles.TileService.onTileResourcesRequest.
This image can have optional overlay on top of it, that is usually a dark color with opacity. This is highly recommended to be added when there's additional content like text on top of image, to improve readability.
If this is used in imageButton as image button with no other content, overlayColor can be omitted, and the overlay color on top of the image would be ignored.
| Parameters | |
|---|---|
resource: ResourceBuilders.ImageResource |
An Image resource, used in the layout in the place of this element. |
protoLayoutResourceId: String? = null |
The optional protolayout resource id of the icon. |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. |
width: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.width |
The width of an image. Usually, this matches the width of the parent component this is used in. |
height: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.height |
The height of an image. Usually, this matches the height of the parent component this is used in. |
overlayColor: LayoutColor? = defaultBackgroundImageStyle.overlayColor |
The color used to provide the overlay over the image for better readability. It's recommended to use |
contentScaleMode: Int = defaultBackgroundImageStyle.contentScaleMode |
The content scale mode for the image to define how image will adapt to the given size @throws IllegalStateException if this method is called without |
button
fun MaterialScope.button(
onClick: ModifiersBuilders.Clickable,
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: ButtonColors = filledButtonColors(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
style: ButtonStyle = defaultButtonStyle(),
horizontalAlignment: Int = if (iconContent == null && secondaryLabelContent == null) { HORIZONTAL_ALIGN_CENTER } else { HORIZONTAL_ALIGN_START },
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 pill shape button that offers up to three slots to take content representing vertically stacked label and secondary label, and an icon next to it.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { button( onClick = clickable, modifier = LayoutModifier.contentDescription("Pill shape button"), width = expand(), height = expand(), labelContent = { text("First label".layoutString) }, secondaryLabelContent = { text("Second label".layoutString) }, iconContent = { icon("id") }, ) } ) }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.LayoutElementBuilders.Box import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { // Button with custom content inside button( onClick = clickable, modifier = LayoutModifier.contentDescription("Big button with image background") .background(colorScheme.primary), width = expand(), height = expand(), labelContent = { // This can be further built. Box.Builder().build() }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The icon slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this button. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this button. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the button's shape, in other words the corner radius for this button. If changing these to radius smaller than |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the button. It is recommended to use the default styling that is automatically provided by only calling |
style: ButtonStyle = defaultButtonStyle() |
The style which provides the attribute values required for constructing this pill shape button and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
horizontalAlignment: Int = if (iconContent == null && secondaryLabelContent == null) {
HORIZONTAL_ALIGN_CENTER
} else {
HORIZONTAL_ALIGN_START
} |
The horizontal placement of the |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the button's edge. It's highly recommended to keep the default. |
buttonGroup
fun MaterialScope.buttonGroup(
width: DimensionBuilders.ContainerDimension = expand(),
height: DimensionBuilders.ContainerDimension = expand(),
spacing: @Dimension(unit = 0) Float = DEFAULT_SPACER_SIZE_DP,
content: ButtonGroupScope.() -> Unit
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 component-layout that places its children in a horizontal sequence.
These behave as a group which fill the available space to maximize on screen real estate. The color and size of the child elements should be changed in order to create hierarchy and priority.
The width and height of the Button/Card should be flexible (set to androidx.wear.protolayout.DimensionBuilders.expand or androidx.wear.protolayout.DimensionBuilders.weight) and their proportion should be either equal or weight based. However the buttonGroup displays correctly too if the sizes of elements provided are set to a fixed width/height, although it can lead to more empty space on large screen sizes.
A buttonGroup with more than one row can be created by using multiple buttonGroup and Spacers inside a androidx.wear.protolayout.LayoutElementBuilders.Column:
Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(buttonGroup {...})
.addContent(DEFAULT_SPACER_BETWEEN_BUTTON_GROUPS)
.addContent(buttonGroup {...})
.build()
}
Note that, having more than 2 rows in a Column could lead to too small height of elements that aren't in line with minimum tap target.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.DimensionBuilders.weight import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle import androidx.wear.protolayout.material3.DataCardStyle.Companion.largeCompactDataCardStyle import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconDataCard import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textDataCard import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with text"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("1km".layoutString) }, content = { this.text("Run".layoutString) }, secondaryText = { this.text("Nice!".layoutString) }, ) } buttonGroupItem { iconDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with icon"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("2km".layoutString) }, secondaryIcon = { icon("id") }, content = { this.text("Run".layoutString) }, ) } buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription( "Compact Data Card without icon or secondary label" ), width = weight(3f), height = expand(), colors = filledVariantCardColors(), style = largeCompactDataCardStyle(), title = { this.text("10:30".layoutString) }, content = { this.text("PM".layoutString) }, ) } } } ) }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), iconContent = { icon("id1") }, ) } buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, iconContent = { icon("id2") }, ) } buttonGroupItem { textButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, labelContent = { text("Dec".layoutString) }, ) } } } ) }
| Parameters | |
|---|---|
width: DimensionBuilders.ContainerDimension = expand() |
The width of this button group |
height: DimensionBuilders.ContainerDimension = expand() |
The height of this button group |
spacing: @Dimension(unit = 0) Float = DEFAULT_SPACER_SIZE_DP |
The amount of spacing between buttons |
content: ButtonGroupScope.() -> Unit |
The content for each child. The UX guidance is to use no more than 3 elements within a this button group. |
card
fun MaterialScope.card(
onClick: ModifiersBuilders.Clickable,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
contentPadding: ModifiersBuilders.Padding = padding(DEFAULT_CONTENT_PADDING),
content: MaterialScope.() -> LayoutElementBuilders.LayoutElement
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 clickable component card that offers a single slot to take any content.
It can be used as the container for more opinionated Card components that take specific content such as icons, images, primary label, secondary label, etc.
The Card is Rectangle shaped with some rounded corners by default. It is highly recommended to set its width and height to fill the available space, by expand or weight for optimal experience across different screen sizes.
It can be used for displaying any clickable container with additional data, text or graphics.
It is highly recommended to set its height to fill the available space, with expand for optimal experience across different screen sizes.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.backgroundImage import androidx.wear.protolayout.material3.card import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { card( onClick = clickable, modifier = LayoutModifier.contentDescription("Card with image background") .clickable(id = "card"), width = expand(), height = expand(), backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }, ) { text("Content of the Card!".layoutString) } } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this card. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this card. It's highly recommended to set this to |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the card. It is recommended to use the default styling that is automatically provided by only calling |
contentPadding: ModifiersBuilders.Padding = padding(DEFAULT_CONTENT_PADDING) |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
content: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The inner content to be put inside of this card. |
circularProgressIndicator
fun MaterialScope.circularProgressIndicator(
staticProgress: Float = 0.0f,
dynamicProgress: DynamicBuilders.DynamicFloat? = null,
modifier: LayoutModifier = LayoutModifier,
startAngleDegrees: Float = 0.0f,
endAngleDegrees: Float = startAngleDegrees + 360F,
strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH,
gapSize: @Dimension(unit = 0) Float = calculateRecommendedGapSize(strokeWidth),
colors: ProgressIndicatorColors = defaultProgressIndicatorStyle.color ?: filledProgressIndicatorColors(),
size: DimensionBuilders.ContainerDimension = expand()
): LayoutElementBuilders.Box
ProtoLayout Material3 design circular progress indicator.
Note that, the proper implementation of this component requires a ProtoLayout renderer with version equal to or above 1.403. When the renderer is lower than 1.403, this component will automatically fallback to an implementation with reduced features, without support for expandable size, and start/end transition.
This component consumes 3 animation quotas when dynamicProgress is specified with animation by the caller. It is highly recommend to use the recommendedAnimationSpec to animate the progress.
The progress indicator's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.dp import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledVariantProgressIndicatorColors import androidx.wear.protolayout.material3.circularProgressIndicator import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text materialScope(context, deviceParameters) { circularProgressIndicator( dynamicProgress = DynamicFloat.animate( 0.0F, 1.1F, CircularProgressIndicatorDefaults.recommendedAnimationSpec, ), startAngleDegrees = 200F, endAngleDegrees = 520F, colors = filledVariantProgressIndicatorColors(), size = dp(85F), ) }
| Parameters | |
|---|---|
staticProgress: Float = 0.0f |
The static progress of this progress indicator where 0 represent no progress and 1 represents completion. Progress above 1 is also allowed. If |
dynamicProgress: DynamicBuilders.DynamicFloat? = null |
The dynamic progress of this progress indicator where 0 represent no progress and 1 represents completion. Progress above 1 is also allowed. If not provided, the |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
startAngleDegrees: Float = 0.0f |
The starting position of the progress arc, measured clockwise in degrees from the 12 o'clock position. |
endAngleDegrees: Float = startAngleDegrees + 360F |
The ending position of the progress arc, measured clockwise in degrees from 12 o'clock position. Its value must be bigger than |
strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH |
The stroke width for the progress indicator. The recommended values are |
gapSize: @Dimension(unit = 0) Float = 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. |
colors: ProgressIndicatorColors = defaultProgressIndicatorStyle.color ?: filledProgressIndicatorColors() |
|
size: DimensionBuilders.ContainerDimension = expand() |
The bounding box size of this progress indicator, applies to both width and height. The indicator arc and track arc are located on the largest circle that can be inscribed inside. It is highly recommended for the progress indicator in a graphics card to have its size as |
| Throws | |
|---|---|
kotlin.IllegalArgumentException |
When |
compactButton
fun MaterialScope.compactButton(
onClick: ModifiersBuilders.Clickable,
modifier: LayoutModifier = LayoutModifier,
labelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: ButtonColors = filledButtonColors(),
horizontalAlignment: Int = if (iconContent != null && labelContent != null) { HORIZONTAL_ALIGN_START } else { HORIZONTAL_ALIGN_CENTER },
contentPadding: ModifiersBuilders.Padding = Padding.Builder() .setStart(COMPACT_BUTTON_DEFAULT_CONTENT_PADDING_DP.toDp()) .setEnd(COMPACT_BUTTON_DEFAULT_CONTENT_PADDING_DP.toDp()) .build()
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 compact button that offers up to two slots to take horizontally stacked content representing an icon and text next to it.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.compactButton import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { compactButton( onClick = clickable, modifier = LayoutModifier.contentDescription("Compact button"), width = expand(), labelContent = { text("Action".layoutString) }, iconContent = { icon("id") }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
labelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by calling |
iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The icon slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this button. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the button's shape, in other words the corner radius for this button. If changing these to radius smaller than |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
horizontalAlignment: Int = if (iconContent != null && labelContent != null) {
HORIZONTAL_ALIGN_START
} else {
HORIZONTAL_ALIGN_CENTER
} |
The horizontal placement of the |
contentPadding: ModifiersBuilders.Padding = Padding.Builder()
.setStart(COMPACT_BUTTON_DEFAULT_CONTENT_PADDING_DP.toDp())
.setEnd(COMPACT_BUTTON_DEFAULT_CONTENT_PADDING_DP.toDp())
.build() |
The inner padding used to prevent inner content from being too close to the button's edge. It's highly recommended to keep the default. |
graphicDataCard
fun MaterialScope.graphicDataCard(
onClick: ModifiersBuilders.Clickable,
graphic: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: CardColors = filledCardColors(),
style: GraphicDataCardStyle = defaultGraphicDataCardStyle(),
horizontalAlignment: Int = HORIZONTAL_ALIGN_START,
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 graphic data card that offers a slot for graphic data such as progress indicator and up to 2 vertically stacked slots, usually for textual description.
It is highly recommended to set its height to fill the available space, with expand for optimal experience across different screen sizes.
The card's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledTonalProgressIndicatorColors import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.largeGraphicDataCardStyle import androidx.wear.protolayout.material3.graphicDataCard import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.segmentedCircularProgressIndicator import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { graphicDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with graphic"), height = expand(), colors = filledVariantCardColors(), style = largeGraphicDataCardStyle(), title = { text("1,234".layoutString) }, content = { icon("steps") }, graphic = { segmentedCircularProgressIndicator( segmentCount = 5, staticProgress = 0.5F, colors = filledTonalProgressIndicatorColors(), ) }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
graphic: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying graphic data, such as |
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying the title of the card, expected to be one line of text. Uses |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The optional body content of the card. Uses |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this card. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the card's shape, in other words the corner radius for this card. If changing these to radius smaller than |
colors: CardColors = filledCardColors() |
The colors to be used for a background and inner content of this card. Specified colors can be |
style: GraphicDataCardStyle = defaultGraphicDataCardStyle() |
The style which provides the attribute values required for constructing this data card and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. It is highly recommended to use one of |
horizontalAlignment: Int = HORIZONTAL_ALIGN_START |
The horizontal placement of the |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
icon
fun MaterialScope.icon(
protoLayoutResourceId: String,
width: DimensionBuilders.ImageDimension = defaultIconStyle.width,
height: DimensionBuilders.ImageDimension = defaultIconStyle.height,
tintColor: LayoutColor = defaultIconStyle.tintColor
): LayoutElementBuilders.LayoutElement
Returns the icon components with the defined style.
Material components provide proper defaults for this icon. In order to take advantage of those, this should be used with the resource ID only: icon("id").
| Parameters | |
|---|---|
protoLayoutResourceId: String |
The protolayout resource id of the icon. Note that, this is not an Android resource id. |
width: DimensionBuilders.ImageDimension = defaultIconStyle.width |
The width of the icon. |
height: DimensionBuilders.ImageDimension = defaultIconStyle.height |
The height of the icon. |
tintColor: LayoutColor = defaultIconStyle.tintColor |
The color used to tint the icon. |
icon
fun MaterialScope.icon(
resource: ResourceBuilders.ImageResource,
protoLayoutResourceId: String? = null,
width: DimensionBuilders.ImageDimension = defaultIconStyle.width,
height: DimensionBuilders.ImageDimension = defaultIconStyle.height,
tintColor: LayoutColor = defaultIconStyle.tintColor
): LayoutElementBuilders.LayoutElement
Returns the icon components with the defined style which will be automatically registered as a resource.
Material components provide proper defaults for this icon. In order to take advantage of those, this should be used with the resource ID only: icon(imageResource).
Note that, by using this method, there's no need to register resource for Tiles in androidx.wear.tiles.TileService.onTileResourcesRequest.
| Parameters | |
|---|---|
resource: ResourceBuilders.ImageResource |
An Image resource, used in the layout in the place of this element. |
protoLayoutResourceId: String? = null |
The optional protolayout resource id of the icon. |
width: DimensionBuilders.ImageDimension = defaultIconStyle.width |
The width of the icon. |
height: DimensionBuilders.ImageDimension = defaultIconStyle.height |
The height of the icon. |
tintColor: LayoutColor = defaultIconStyle.tintColor |
The color used to tint the icon. @throws IllegalStateException if this method is called without |
iconButton
fun MaterialScope.iconButton(
onClick: ModifiersBuilders.Clickable,
iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: ButtonColors = filledButtonColors(),
style: IconButtonStyle = defaultIconButtonStyle(),
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 icon button that offers a single slot to take content representing icon, for example icon.
The button is usually either a circular shape with the same width and height, or highly recommended stadium shape occupying available space with width and height set to expand or weight, usually arranged with the buttonGroup.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), iconContent = { icon("id1") }, ) } buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, iconContent = { icon("id2") }, ) } buttonGroupItem { textButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, labelContent = { text("Dec".layoutString) }, ) } } } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The icon slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this button. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this button. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the button's shape, in other words the corner radius for this button. If changing these to radius smaller than |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
style: IconButtonStyle = defaultIconButtonStyle() |
The style which provides the attribute values required for constructing this icon button and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the button's edge. It's highly recommended to keep the default. |
iconDataCard
fun MaterialScope.iconDataCard(
onClick: ModifiersBuilders.Clickable,
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
secondaryIcon: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.large,
colors: CardColors = filledCardColors(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
style: DataCardStyle = if (secondaryIcon == null) { defaultCompactDataCardStyle() } else { defaultDataCardStyle() },
titleContentPlacement: TitleContentPlacementInDataCard = TitleContentPlacementInDataCard.Bottom,
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 data card that offers up to 3 vertically stacked slots, usually text or numeral based, with icon.
Slots can have multiple placements, depending on their presence and titleContentPlacement:
-
If
secondaryIconare set, it will be placed first whentitleContentPlacementis set toTitleContentPlacementInDataCard.Bottom, or last iftitleContentPlacementis set toTitleContentPlacementInDataCard.Top. -
If
secondaryIconis not set, thistextDataCardis considered ascompactdata card, with title and content only.
This card works well in buttonGroup with cards width and height set to expand.
The card's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.DimensionBuilders.weight import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle import androidx.wear.protolayout.material3.DataCardStyle.Companion.largeCompactDataCardStyle import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconDataCard import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textDataCard import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with text"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("1km".layoutString) }, content = { this.text("Run".layoutString) }, secondaryText = { this.text("Nice!".layoutString) }, ) } buttonGroupItem { iconDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with icon"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("2km".layoutString) }, secondaryIcon = { icon("id") }, content = { this.text("Run".layoutString) }, ) } buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription( "Compact Data Card without icon or secondary label" ), width = weight(3f), height = expand(), colors = filledVariantCardColors(), style = largeCompactDataCardStyle(), title = { this.text("10:30".layoutString) }, content = { this.text("PM".layoutString) }, ) } } } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying the title of the card, expected to be one line of text. Uses |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The optional body content of the card. Uses |
secondaryIcon: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot for displaying small icon, such as |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this card. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this card. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.large |
Defines the card's shape, in other words the corner radius for this card. If changing these to radius smaller than |
colors: CardColors = filledCardColors() |
The colors to be used for a background and inner content of this card. If the background image is also specified, the image will be laid out on top of the background color. In case of the fully opaque background image, then the background color will not be shown. Specified colors can be |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the card. It is recommended to use the default styling that is automatically provided by only calling |
style: DataCardStyle = if (secondaryIcon == null) {
defaultCompactDataCardStyle()
} else {
defaultDataCardStyle()
} |
The style which provides the attribute values required for constructing this data card and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. It is highly recommended to use one of |
titleContentPlacement: TitleContentPlacementInDataCard = TitleContentPlacementInDataCard.Bottom |
The placement of the |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
iconEdgeButton
fun MaterialScope.iconEdgeButton(
onClick: ModifiersBuilders.Clickable,
modifier: LayoutModifier = LayoutModifier,
colors: ButtonColors = filledButtonColors(),
iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 component edge button that offers a single slot to take an icon or similar round, small content.
The edge button is intended to be used at the bottom of a round screen. It has a special shape with its bottom almost follows the screen's curvature. It has fixed height, and takes 1 line of icon. This button represents the most important action on the screen, and it must occupy the whole horizontal space in its position as well as being anchored to the screen bottom.
This component is not intended to be used with an image background.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconEdgeButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription materialScope(context, deviceConfiguration) { iconEdgeButton( onClick = clickable, modifier = LayoutModifier.contentDescription("Description of a button"), ) { icon(protoLayoutResourceId = "id") } }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The icon slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
imageButton
fun MaterialScope.imageButton(
onClick: ModifiersBuilders.Clickable,
backgroundContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp(),
height: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp()
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 clickable image button that doesn't offer additional slots, only image (for example backgroundImage as a background).
The button is usually stadium or circle shaped with fully rounded corners by default. It is highly recommended to set its width and height to fill the available space, by expand or weight for optimal experience across different screen sizes, and use buttonGroup to arrange them.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.backgroundImage import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.imageButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { imageButton( onClick = clickable, modifier = LayoutModifier.contentDescription("Big button with image background"), width = expand(), height = expand(), backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
backgroundContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The background object to be used behind the content in the button. It is recommended to use the default styling that is automatically provided by only calling |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
width: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp() |
The width of this button. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp() |
The height of this button. It's highly recommended to set this to |
primaryLayout
fun MaterialScope.primaryLayout(
mainSlot: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
titleSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
bottomSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
labelForBottomSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
onClick: ModifiersBuilders.Clickable? = null,
margins: PrimaryLayoutMargins = DEFAULT_PRIMARY_LAYOUT_MARGIN
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 full screen layout that represents a suggested Material3 layout style that is responsive and takes care of the elements placement, together with the recommended margin and padding applied.
This layout is meant to occupy the whole screen, so nothing else should be added on top of it.
On the top, there is an icon that will be automatically placed by the system, followed by the optional title slot. The icon slot needs to be reserved for the whole ProtoLayout Layout and no other content should be added at the top of the screen as it will be overlapped with the system placed icon.
At the bottom, there is an optional fixed slot for either {@link EdgeButton} as a main action or small non tappable content.
The middle of the layout is main content, that will fill the available space. For the best results across different screen sizes, it's recommended that this content's dimension are also DimensionBuilders.expand or DimensionBuilders.weight. Additional content in the main one can be added after a 225dp breakpoint.
import androidx.wear.protolayout.LayoutElementBuilders import androidx.wear.protolayout.LayoutElementBuilders.Box import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement import androidx.wear.protolayout.ModifiersBuilders import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconEdgeButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( titleSlot = { text("App title".layoutString) }, mainSlot = { buttonGroup { // To be populated with proper components buttonGroupItem { LayoutElementBuilders.Box.Builder() .setModifiers( ModifiersBuilders.Modifiers.Builder() .setBackground( ModifiersBuilders.Background.Builder() .setCorner(shapes.small) .build() ) .build() ) .build() } } }, // Adjust margins as the corner of the inner content is on the square side. margins = MAX_PRIMARY_LAYOUT_MARGIN, bottomSlot = { iconEdgeButton( onClick = clickable, modifier = LayoutModifier.contentDescription("Description"), ) { icon("id") } }, ) }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.backgroundImage import androidx.wear.protolayout.material3.card import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { card( onClick = clickable, modifier = LayoutModifier.contentDescription("Card with image background") .clickable(id = "card"), width = expand(), height = expand(), backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }, ) { text("Content of the Card!".layoutString) } } ) }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), iconContent = { icon("id1") }, ) } buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, iconContent = { icon("id2") }, ) } buttonGroupItem { textButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, labelContent = { text("Dec".layoutString) }, ) } } } ) }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledTonalProgressIndicatorColors import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.largeGraphicDataCardStyle import androidx.wear.protolayout.material3.graphicDataCard import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.segmentedCircularProgressIndicator import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { graphicDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with graphic"), height = expand(), colors = filledVariantCardColors(), style = largeGraphicDataCardStyle(), title = { text("1,234".layoutString) }, content = { icon("steps") }, graphic = { segmentedCircularProgressIndicator( segmentCount = 5, staticProgress = 0.5F, colors = filledTonalProgressIndicatorColors(), ) }, ) } ) }
import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clearSemantics import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( titleSlot = { text("App title".layoutString, modifier = LayoutModifier.clearSemantics()) }, mainSlot = { text("Main content".layoutString) }, bottomSlot = { text("Bottom slot".layoutString, modifier = LayoutModifier.clearSemantics()) }, labelForBottomSlot = { text("Bottom label".layoutString, modifier = LayoutModifier.clearSemantics()) }, ) }
| Parameters | |
|---|---|
mainSlot: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The main, central content for this layout. It's recommended for this content to fill the available width and height for the best result across different screen size. This layout places proper padding to prevent content from being cropped by the screen. Note that depending on the corner shapes and different elements on the screen, there might be a need to change padding on some of the elements in this slot. The content passed here can also have an additional content value added to it, after |
titleSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The app title in the top slot, just below the icon. This should be one line of |
bottomSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The content for bottom slot in this layout, that will be anchored to the bottom edge of the screen. This should be either a small non tappable content such as Text with optional label for it or tappable main action with |
labelForBottomSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The label displayed just above the |
onClick: ModifiersBuilders.Clickable? = null |
The clickable action for whole layout. If any area (outside of other added tappable components) is clicked, it will fire the associated action. |
margins: PrimaryLayoutMargins = DEFAULT_PRIMARY_LAYOUT_MARGIN |
The customized outer margin that will be applied as following: * It is highly recommended to use provided constants for these margins - |
segmentedCircularProgressIndicator
fun MaterialScope.segmentedCircularProgressIndicator(
segmentCount: @IntRange(from = 1) Int,
staticProgress: Float = 0.0f,
dynamicProgress: DynamicBuilders.DynamicFloat? = null,
modifier: LayoutModifier = LayoutModifier,
startAngleDegrees: Float = 0.0f,
endAngleDegrees: Float = startAngleDegrees + 360F,
strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH,
gapSize: @Dimension(unit = 0) Float = calculateRecommendedGapSize(strokeWidth),
colors: ProgressIndicatorColors = defaultProgressIndicatorStyle.color ?: filledProgressIndicatorColors(),
size: DimensionBuilders.ContainerDimension = expand()
): LayoutElementBuilders.Box
ProtoLayout Material3 design segmented circular progress indicator.
A segmented variant of circularProgressIndicator that is divided into equally sized segments.
Note that, the proper implementation of this component requires a ProtoLayout renderer with version equal to or above 1.403. When the renderer is lower than 1.403, this component will automatically fallback to an implementation with reduced features, without support for multiple segments, expandable size, and start/end transition.
This component consumes 2 animation quotas when dynamicProgress is specified with animation by the caller. It is highly recommend to use the recommendedAnimationSpec to animate the progress.
The progress indicator's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.dp import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledVariantProgressIndicatorColors import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.segmentedCircularProgressIndicator import androidx.wear.protolayout.material3.text materialScope(context, deviceParameters) { segmentedCircularProgressIndicator( segmentCount = 5, dynamicProgress = DynamicFloat.animate( 0.0F, 1.1F, CircularProgressIndicatorDefaults.recommendedAnimationSpec, ), startAngleDegrees = 200F, endAngleDegrees = 520F, colors = filledVariantProgressIndicatorColors(), size = dp(85F), ) }
| Parameters | |
|---|---|
segmentCount: @IntRange(from = 1) Int |
Number of equal segments that the progress indicator should be divided into. Has to be a number greater than or equal to 1. |
staticProgress: Float = 0.0f |
The static progress of this progress indicator where 0 represent no progress and 1 represents completion. Progress above 1 is also allowed. If |
dynamicProgress: DynamicBuilders.DynamicFloat? = null |
The dynamic progress of this progress indicator where 0 represent no progress and 1 represents completion. Progress above 1 is also allowed. If not provided, the |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
startAngleDegrees: Float = 0.0f |
The starting position of the progress arc, measured clockwise in degrees from the 12 o'clock position. |
endAngleDegrees: Float = startAngleDegrees + 360F |
The ending position of the progress arc, measured clockwise in degrees from 12 o'clock position. This value must be bigger than |
strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH |
The stroke width for the progress indicator. The recommended values are |
gapSize: @Dimension(unit = 0) Float = 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. |
colors: ProgressIndicatorColors = defaultProgressIndicatorStyle.color ?: filledProgressIndicatorColors() |
|
size: DimensionBuilders.ContainerDimension = expand() |
The bounding box size of this progress indicator, applies to both width and height. The indicator arc and track arc are located on the largest circle that can be inscribed inside. It is highly recommended for the progress indicator in |
| Throws | |
|---|---|
kotlin.IllegalArgumentException |
When |
text
fun MaterialScope.text(
text: LayoutString,
modifier: LayoutModifier = LayoutModifier,
typography: Int = defaultTextElementStyle.typography,
color: LayoutColor = defaultTextElementStyle.color,
italic: Boolean = defaultTextElementStyle.italic,
underline: Boolean = defaultTextElementStyle.underline,
scalable: Boolean = defaultTextElementStyle.scalable ?: TypographyFontSelection.getFontScalability(typography),
maxLines: Int = defaultTextElementStyle.maxLines,
alignment: Int = defaultTextElementStyle.alignment,
overflow: Int = defaultTextElementStyle.overflow,
@RequiresSchemaVersion(major = 1, minor = 400) settings: List<LayoutElementBuilders.FontSetting> = emptyList(),
incrementsForTypographySize: List<Float> = emptyList()
): LayoutElementBuilders.LayoutElement
ProtoLayout component that represents text object holding any information.
There are pre-defined typography styles that can be obtained from Materials token system in Typography.
This text, when added to the titleSlot, bottomSlot and labelForBottomSlot in primaryLayout, is considered as important for accessibility automatically and gets read out by the screen reader even without content description provided in the modifier. This behavior can be removed with LayoutModifier.clearSemantics if not desired. In all other places, this text is considered as not important for accessibility by default unless content description is specifically provided in the modifier.
import androidx.wear.protolayout.material3.Typography import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { text(text = "Hello Material3".layoutString, typography = Typography.DISPLAY_LARGE) }
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString import androidx.wear.protolayout.material3.Typography import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.types.LayoutString import androidx.wear.protolayout.types.asLayoutConstraint materialScope(context, deviceConfiguration) { this.text( text = LayoutString( "Static", DynamicString.constant("Dynamic"), "LongestConstraint".asLayoutConstraint(), ), typography = Typography.DISPLAY_LARGE, color = colorScheme.tertiary, underline = true, maxLines = 5, ) }
import androidx.wear.protolayout.material3.Typography import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { text( text = "Hello Material3".layoutString, typography = Typography.DISPLAY_LARGE, incrementsForTypographySize = listOf(-4f, -2f, 2f), ) }
import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clearSemantics import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( titleSlot = { text("App title".layoutString, modifier = LayoutModifier.clearSemantics()) }, mainSlot = { text("Main content".layoutString) }, bottomSlot = { text("Bottom slot".layoutString, modifier = LayoutModifier.clearSemantics()) }, labelForBottomSlot = { text("Bottom label".layoutString, modifier = LayoutModifier.clearSemantics()) }, ) }
| Parameters | |
|---|---|
text: LayoutString |
The text content for this component. |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. |
typography: Int = defaultTextElementStyle.typography |
The typography from |
color: LayoutColor = defaultTextElementStyle.color |
The color to be applied to this text. It is recommended to use predefined default styles created by each component or |
italic: Boolean = defaultTextElementStyle.italic |
Whether text should be displayed as italic. |
underline: Boolean = defaultTextElementStyle.underline |
Whether text should be displayed as underlined. |
scalable: Boolean = defaultTextElementStyle.scalable ?: TypographyFontSelection.getFontScalability(typography) |
Whether text should scale with the user font size. |
maxLines: Int = defaultTextElementStyle.maxLines |
The maximum number of lines that text can occupy. |
alignment: Int = defaultTextElementStyle.alignment |
The horizontal alignment of the multiple lines of text or one line of text when text overflows. |
overflow: Int = defaultTextElementStyle.overflow |
The overflow strategy when text doesn't have enough space to be shown. |
@RequiresSchemaVersion(major = 1, minor = 400) settings: List<LayoutElementBuilders.FontSetting> = emptyList() |
The collection of font settings to be applied. If more than one Setting with the same axis tag is specified, the first one will be used. Supported settings depend on the font used and renderer version. Each default typography will apply appropriate default setting axes for it ( |
incrementsForTypographySize: List<Float> = emptyList() |
The collection increments for the given |
textButton
fun MaterialScope.textButton(
onClick: ModifiersBuilders.Clickable,
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.full,
colors: ButtonColors = filledButtonColors(),
style: TextButtonStyle = defaultTextButtonStyle(),
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 text button that offers a single slot to take content representing short text, for example text.
The button is usually either a circular shape with the same width and height, or highly recommended stadium shape occupying available space with width and height set to expand or weight, usually arranged with the buttonGroup.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), iconContent = { icon("id1") }, ) } buttonGroupItem { iconButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, iconContent = { icon("id2") }, ) } buttonGroupItem { textButton( onClick = clickable, modifier = LayoutModifier.contentDescription( "Big button with image background" ), width = expand(), height = expand(), shape = shapes.large, labelContent = { text("Dec".layoutString) }, ) } } } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The text slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this button. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this button. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.full |
Defines the button's shape, in other words the corner radius for this button. If changing these to radius smaller than |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
style: TextButtonStyle = defaultTextButtonStyle() |
The style which provides the attribute values required for constructing this text button and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the button's edge. It's highly recommended to keep the default. |
textDataCard
fun MaterialScope.textDataCard(
onClick: ModifiersBuilders.Clickable,
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
secondaryText: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = shapes.large,
colors: CardColors = filledCardColors(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
style: DataCardStyle = if (secondaryText == null) { defaultCompactDataCardStyle() } else { defaultDataCardStyle() },
contentPadding: ModifiersBuilders.Padding = style.innerPadding
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 data card that offers up to 3 vertically stacked slots, usually text or numeral based.
This card works well in buttonGroup with cards width and height is set to expand.
The card's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.DimensionBuilders.weight import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle import androidx.wear.protolayout.material3.DataCardStyle.Companion.largeCompactDataCardStyle import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconDataCard import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textDataCard import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { buttonGroup { buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with text"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("1km".layoutString) }, content = { this.text("Run".layoutString) }, secondaryText = { this.text("Nice!".layoutString) }, ) } buttonGroupItem { iconDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Data Card with icon"), width = weight(1f), height = expand(), colors = filledTonalCardColors(), style = extraLargeDataCardStyle(), title = { this.text("2km".layoutString) }, secondaryIcon = { icon("id") }, content = { this.text("Run".layoutString) }, ) } buttonGroupItem { textDataCard( onClick = clickable, modifier = LayoutModifier.contentDescription( "Compact Data Card without icon or secondary label" ), width = weight(3f), height = expand(), colors = filledVariantCardColors(), style = largeCompactDataCardStyle(), title = { this.text("10:30".layoutString) }, content = { this.text("PM".layoutString) }, ) } } } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying the title of the card, expected to be one line of text. Uses |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The optional body content of the card. Uses |
secondaryText: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot for displaying short, secondary text. Uses |
width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The width of this card. It's highly recommended to set this to |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this card. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = shapes.large |
Defines the card's shape, in other words the corner radius for this card. If changing these to radius smaller than |
colors: CardColors = filledCardColors() |
The colors to be used for a background and inner content of this card. If the background image is also specified, the image will be laid out on top of the background color. In case of the fully opaque background image, then the background color will not be shown. Specified colors can be |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the card. It is recommended to use the default styling that is automatically provided by only calling |
style: DataCardStyle = if (secondaryText == null) {
defaultCompactDataCardStyle()
} else {
defaultDataCardStyle()
} |
The style which provides the attribute values required for constructing this data card and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. It is highly recommended to use one of |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
textEdgeButton
fun MaterialScope.textEdgeButton(
onClick: ModifiersBuilders.Clickable,
modifier: LayoutModifier = LayoutModifier,
colors: ButtonColors = filledButtonColors(),
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement
): LayoutElementBuilders.LayoutElement
ProtoLayout Material3 component edge button that offers a single slot to take a text or similar long and wide content.
The edge button is intended to be used at the bottom of a round screen. It has a special shape with its bottom almost follows the screen's curvature. It has fixed height, and takes 1 line of text. This button represents the most important action on the screen, and it must occupy the whole horizontal space in its position as well as being anchored to the screen bottom.
This component is not intended to be used with an image background.
The button's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textEdgeButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { textEdgeButton( onClick = clickable, modifier = LayoutModifier.contentDescription("Description of a button"), ) { text("Hello".layoutString) } }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
colors: ButtonColors = filledButtonColors() |
The colors used for this button. If not set, |
labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
The label slot for content displayed in this button. It is recommended to use default styling that is automatically provided by only calling |
titleCard
fun MaterialScope.titleCard(
onClick: ModifiersBuilders.Clickable,
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
modifier: LayoutModifier = LayoutModifier,
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension(),
shape: ModifiersBuilders.Corner = if (deviceConfiguration.screenWidthDp.isBreakpoint()) { shapes.extraLarge } else { shapes.large },
colors: CardColors = filledCardColors(),
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null,
style: TitleCardStyle = defaultTitleCardStyle(),
contentPadding: ModifiersBuilders.Padding = style.innerPadding,
horizontalAlignment: Int = if (time == null) HORIZONTAL_ALIGN_CENTER else HORIZONTAL_ALIGN_START
): LayoutElementBuilders.LayoutElement
Opinionated ProtoLayout Material3 title card that offers 1 to 3 slots, usually text based.
Those are vertically stacked title and content, and additional side slot for a time.
It is highly recommended to set its height to fill the available space, with expand for optimal experience across different screen sizes.
The card's colors default to using ColorScheme from the MaterialScope it's defined in, which defaults to dynamicColorScheme, meaning that the colors follow system theme if available on device. If not, or switched off by user, uses fallback ColorScheme defined in its MaterialScope.
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.TitleCardStyle.Companion.largeTitleCardStyle import androidx.wear.protolayout.material3.card import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.titleCard import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) { primaryLayout( mainSlot = { titleCard( onClick = clickable, modifier = LayoutModifier.contentDescription("Title Card"), height = expand(), colors = filledVariantCardColors(), style = largeTitleCardStyle(), title = { text("This is title of the title card".layoutString) }, time = { text("NOW".layoutString) }, content = { text("Content of the Card!".layoutString) }, ) } ) }
| Parameters | |
|---|---|
onClick: ModifiersBuilders.Clickable |
Associated |
title: MaterialScope.() -> LayoutElementBuilders.LayoutElement |
A slot for displaying the title of the card, expected to be one or two lines of text. Uses |
modifier: LayoutModifier = LayoutModifier |
Modifiers to set to this element. It's highly recommended to set a content description using |
content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The optional body content of the card. Uses |
time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Uses |
height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension() |
The height of this card. It's highly recommended to set this to |
shape: ModifiersBuilders.Corner = if (deviceConfiguration.screenWidthDp.isBreakpoint()) {
shapes.extraLarge
} else {
shapes.large
} |
Defines the card's shape, in other words the corner radius for this card. If changing these to radius smaller than |
colors: CardColors = filledCardColors() |
The colors to be used for a background and inner content of this card. If the background image is also specified, the image will be laid out on top of the background color. In case of the fully opaque background image, then the background color will not be shown. Specified colors can be |
backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null |
The background object to be used behind the content in the card. It is recommended to use the default styling that is automatically provided by only calling |
style: TitleCardStyle = defaultTitleCardStyle() |
The style which provides the attribute values required for constructing this title card and its inner content. It also provides default style for the inner content, that can be overridden by each content slot. |
contentPadding: ModifiersBuilders.Padding = style.innerPadding |
The inner padding used to prevent inner content from being too close to the card's edge. It's highly recommended to keep the default. |
horizontalAlignment: Int = if (time == null) HORIZONTAL_ALIGN_CENTER else HORIZONTAL_ALIGN_START |
The horizontal alignment of |