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 textEdgeButton or iconEdgeButton.

ButtonGroupScope

Scope for the children of a buttonGroup

ButtonStyle

Provides style values for the pill shape button component.

CardColors

Represents colors used in card components, such as titleCard or appCard.

ColorScheme

A ColorScheme holds all the named color parameters for a MaterialTheme.

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 primaryLayout's customization.

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 title and content slots in iconDataCard, relative to other optional slots in that type of card.

Objects

ButtonDefaults
ButtonGroupDefaults

Contains the default values used by buttonGroup

CardDefaults
CircularProgressIndicatorDefaults
TitleCardDefaults
Typography

Class holding typography definitions as defined by the Wear Material3 typography specification.

Annotations

Top-level functions summary

ColorScheme
dynamicColorScheme(context: Context, defaultColorScheme: ColorScheme)

Creates a dynamic color scheme.

Boolean

Returns whether the dynamic colors scheme (colors following the system theme) is enabled.

LayoutElementBuilders.LayoutElement
materialScope(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
    allowDynamicTheme: Boolean,
    defaultColorScheme: ColorScheme,
    layout: MaterialScope.() -> 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.

Extension functions summary

LayoutElementBuilders.LayoutElement
MaterialScope.appCard(
    onClick: ModifiersBuilders.Clickable,
    title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    avatar: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    label: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: CardColors,
    backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    style: AppCardStyle,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 app card that offers up to 5 slots, usually text based.

LayoutElementBuilders.LayoutElement
MaterialScope.avatarButton(
    onClick: ModifiersBuilders.Clickable,
    labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    avatarContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: ButtonColors,
    style: AvatarButtonStyle,
    horizontalAlignment: Int,
    contentPadding: ModifiersBuilders.Padding
)

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.

LayoutElementBuilders.LayoutElement
MaterialScope.avatarImage(
    protoLayoutResourceId: String,
    width: DimensionBuilders.ImageDimension,
    height: DimensionBuilders.ImageDimension,
    modifier: LayoutModifier,
    contentScaleMode: Int
)

Returns the avatar image with the defined style.

LayoutElementBuilders.LayoutElement
MaterialScope.backgroundImage(
    protoLayoutResourceId: String,
    modifier: LayoutModifier,
    width: DimensionBuilders.ImageDimension,
    height: DimensionBuilders.ImageDimension,
    overlayColor: LayoutColor,
    overlayWidth: DimensionBuilders.ContainerDimension,
    overlayHeight: DimensionBuilders.ContainerDimension,
    contentScaleMode: Int
)

Returns the image background with the defined style.

LayoutElementBuilders.LayoutElement
MaterialScope.button(
    onClick: ModifiersBuilders.Clickable,
    labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    secondaryLabelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: ButtonColors,
    backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    style: ButtonStyle,
    horizontalAlignment: Int,
    contentPadding: ModifiersBuilders.Padding
)

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.

LayoutElementBuilders.LayoutElement
MaterialScope.buttonGroup(
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    spacing: @Dimension(unit = 0) Float,
    content: ButtonGroupScope.() -> Unit
)

ProtoLayout Material3 component-layout that places its children in a horizontal sequence.

LayoutElementBuilders.LayoutElement

ProtoLayout Material3 clickable component card that offers a single slot to take any content.

LayoutElementBuilders.LayoutElement
MaterialScope.circularProgressIndicator(
    staticProgress: Float,
    dynamicProgress: DynamicBuilders.DynamicFloat?,
    modifier: LayoutModifier,
    startAngleDegrees: Float,
    endAngleDegrees: Float,
    strokeWidth: @Dimension(unit = 0) Float,
    gapSize: @Dimension(unit = 0) Float,
    colors: ProgressIndicatorColors,
    size: DimensionBuilders.ContainerDimension
)

Protolayout Material3 design circular progress indicator.

LayoutElementBuilders.LayoutElement
MaterialScope.compactButton(
    onClick: ModifiersBuilders.Clickable,
    modifier: LayoutModifier,
    labelContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    iconContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    width: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: ButtonColors,
    horizontalAlignment: Int,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 compact button that offers up to two slots to take horizontally stacked content representing an icon and text next to it.

LayoutElementBuilders.LayoutElement
MaterialScope.graphicDataCard(
    onClick: ModifiersBuilders.Clickable,
    graphic: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: CardColors,
    style: GraphicDataCardStyle,
    horizontalAlignment: Int,
    contentPadding: ModifiersBuilders.Padding
)

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.

LayoutElementBuilders.LayoutElement
MaterialScope.icon(
    protoLayoutResourceId: String,
    size: DimensionBuilders.ImageDimension,
    tintColor: LayoutColor
)

Returns the icon components with the defined style.

LayoutElementBuilders.LayoutElement
MaterialScope.iconButton(
    onClick: ModifiersBuilders.Clickable,
    iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: ButtonColors,
    style: IconButtonStyle,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 icon button that offers a single slot to take content representing icon, for example icon.

LayoutElementBuilders.LayoutElement
MaterialScope.iconDataCard(
    onClick: ModifiersBuilders.Clickable,
    title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    secondaryIcon: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: CardColors,
    backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    style: DataCardStyle,
    titleContentPlacement: TitleContentPlacementInDataCard,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 data card that offers up to 3 vertically stacked slots, usually text or numeral based, with icon.

LayoutElementBuilders.LayoutElement
MaterialScope.iconEdgeButton(
    onClick: ModifiersBuilders.Clickable,
    modifier: LayoutModifier,
    colors: ButtonColors,
    iconContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement
)

ProtoLayout Material3 component edge button that offers a single slot to take an icon or similar round, small content.

LayoutElementBuilders.LayoutElement

ProtoLayout Material3 clickable image button that doesn't offer additional slots, only image (for example backgroundImage as a background.

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.

LayoutElementBuilders.LayoutElement
MaterialScope.segmentedCircularProgressIndicator(
    segmentCount: @IntRange(from = 1) Int,
    staticProgress: Float,
    dynamicProgress: DynamicBuilders.DynamicFloat?,
    modifier: LayoutModifier,
    startAngleDegrees: Float,
    endAngleDegrees: Float,
    strokeWidth: @Dimension(unit = 0) Float,
    gapSize: @Dimension(unit = 0) Float,
    colors: ProgressIndicatorColors,
    size: DimensionBuilders.ContainerDimension
)

Protolayout Material3 design segmented circular progress indicator.

LayoutElementBuilders.LayoutElement
MaterialScope.text(
    text: LayoutString,
    typography: Int,
    color: LayoutColor,
    italic: Boolean,
    underline: Boolean,
    scalable: Boolean,
    maxLines: Int,
    multilineAlignment: Int,
    overflow: Int,
    modifiers: LayoutModifier
)

ProtoLayout component that represents text object holding any information.

LayoutElementBuilders.LayoutElement
MaterialScope.textButton(
    onClick: ModifiersBuilders.Clickable,
    labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: ButtonColors,
    style: TextButtonStyle,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 text button that offers a single slot to take content representing short text, for example text.

LayoutElementBuilders.LayoutElement
MaterialScope.textDataCard(
    onClick: ModifiersBuilders.Clickable,
    title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    secondaryText: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    width: DimensionBuilders.ContainerDimension,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: CardColors,
    backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    style: DataCardStyle,
    contentPadding: ModifiersBuilders.Padding
)

Opinionated ProtoLayout Material3 data card that offers up to 3 vertically stacked slots, usually text or numeral based.

LayoutElementBuilders.LayoutElement
MaterialScope.textEdgeButton(
    onClick: ModifiersBuilders.Clickable,
    modifier: LayoutModifier,
    colors: ButtonColors,
    labelContent: MaterialScope.() -> LayoutElementBuilders.LayoutElement
)

ProtoLayout Material3 component edge button that offers a single slot to take a text or similar long and wide content.

LayoutElementBuilders.LayoutElement
MaterialScope.titleCard(
    onClick: ModifiersBuilders.Clickable,
    title: MaterialScope.() -> LayoutElementBuilders.LayoutElement,
    modifier: LayoutModifier,
    content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    time: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    height: DimensionBuilders.ContainerDimension,
    shape: ModifiersBuilders.Corner,
    colors: CardColors,
    backgroundContent: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)?,
    style: TitleCardStyle,
    contentPadding: ModifiersBuilders.Padding,
    horizontalAlignment: Int
)

Opinionated ProtoLayout Material3 title card that offers 1 to 3 slots, usually text based.

Top-level functions

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 watchface. If the user changes the watchface colors, this color scheme will change accordingly. This function checks whether the dynamic color scheme can be used and returns defaultColorScheme otherwise.

Parameters
context: Context

The context required to get system resource data.

defaultColorScheme: ColorScheme = ColorScheme()

The fallback ColorScheme to return if the dynamic color scheme is switched off or unavailable on this device.

isDynamicColorSchemeEnabled

fun isDynamicColorSchemeEnabled(context: Context): Boolean

Returns whether the dynamic colors scheme (colors following the system theme) is enabled.

If enabled, and elements or MaterialScope are opted in to using dynamic theme, colors will change whenever system theme changes.

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.

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

If 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 allowDynamicTheme is false, or when dynamic theming is disabled by the system or user. If not set, defaults to default theme.

layout: MaterialScope.() -> LayoutElementBuilders.LayoutElement

Scoped slot for the content of layout to be displayed

Extension functions

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:

  1. a small optional image, such as avatarImage

  2. label, which is expected to be a short text

  3. 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.

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 Clickable for click events. When the card is clicked it will fire the associated action.

title: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying the title of the card, expected to be one line of text. Uses CardColors.titleColor color by default.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The optional body content of the card. Uses CardColors.contentColor color by default.

avatar: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

An optional slot in header for displaying small image, such as avatarImage.

label: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

An optional slot in header for displaying short, label text. Uses CardColors.labelColor color by default.

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 CardColors.timeColor color by default.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this card. It's highly recommended to leave this with default value as wrap if there's only 1 card on the screen. If there are two cards, it is highly recommended to set this to expand and use the smaller styles.

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

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 CardDefaults.filledCardColors for high emphasis card, CardDefaults.filledVariantCardColors for high/medium emphasis card, CardDefaults.filledTonalCardColors for low/medium emphasis card, CardDefaults.imageBackgroundCardColors for card with image as a background or custom built CardColors.

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 backgroundImage with the content. It can be combined with the specified colors's background color behind it.

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.

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.

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 Clickable for click events. When the button is clicked it will fire the associated action.

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 text.

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 avatarImage with the resource ID. Width and height of this element should be set to expand.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

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 text.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this button. It's highly recommended to set this to expand or weight

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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 avatarContent. This should be HORIZONTAL_ALIGN_START to place the avatarContent on the start side of the button, or HORIZONTAL_ALIGN_END to place in on the end side. HORIZONTAL_ALIGN_CENTER will be ignored and replaced with HORIZONTAL_ALIGN_START.

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.

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

fun MaterialScope.backgroundImage(
    protoLayoutResourceId: String,
    modifier: LayoutModifier = LayoutModifier,
    width: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.width,
    height: DimensionBuilders.ImageDimension = defaultBackgroundImageStyle.height,
    overlayColor: LayoutColor = defaultBackgroundImageStyle.overlayColor,
    overlayWidth: DimensionBuilders.ContainerDimension = defaultBackgroundImageStyle.overlayWidth,
    overlayHeight: DimensionBuilders.ContainerDimension = defaultBackgroundImageStyle.overlayHeight,
    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").

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 ColorScheme.background color with 60% opacity.

overlayWidth: DimensionBuilders.ContainerDimension = defaultBackgroundImageStyle.overlayWidth

The width of the overlay on top of the image background

overlayHeight: DimensionBuilders.ContainerDimension = defaultBackgroundImageStyle.overlayHeight

The height of the overlay on top of the image background

contentScaleMode: Int = defaultBackgroundImageStyle.contentScaleMode

The content scale mode for the image to define how image will adapt to the given size

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.

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.backgroundColor
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")
                            .backgroundColor(colorScheme.primary),
                    width = expand(),
                    height = expand(),
                    labelContent = {
                        // This can be further built.
                        Box.Builder().build()
                    }
                )
            }
        )
    }
Parameters
onClick: ModifiersBuilders.Clickable

Associated Clickable for click events. When the button is clicked it will fire the associated action.

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 text.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

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 text.

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 icon with the resource ID.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this button. It's highly recommended to set this to expand or weight

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this button. It's highly recommended to set this to expand or weight

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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 backgroundImage with the content. It can be combined with the specified ButtonColors.containerColor behind it.

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 labelContent and secondaryLabelContent content. If iconContent is present, this should be HORIZONTAL_ALIGN_START. Defaults to HORIZONTAL_ALIGN_CENTER if only labelContent is present, otherwise it default to HORIZONTAL_ALIGN_START.

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.

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.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.

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.

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.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 Clickable for click events. When the card is clicked it will fire the associated action.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription. If LayoutModifier.background modifier is used and the the background image is also specified, the image will be laid out on top of this color. In case of the fully opaque background image, then the background color will not be shown. If LayoutModifier.clip modifier is used to change the shape of the card to radius smaller than Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if changing to Shapes.full, using minPrimaryLayoutMargins can be considered.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this card. It's highly recommended to set this to expand or weight

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this card. It's highly recommended to set this to expand or weight

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 backgroundImage with the content. It can be combined with the specified LayoutModifier.background behind it.

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 = filledProgressIndicatorColors(),
    size: DimensionBuilders.ContainerDimension = expand()
): LayoutElementBuilders.LayoutElement

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, overflow, and start/end transition.

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 is also set, this static value will only be used when the dynamic value cannot be evaluated. By default it equals to 0.

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 staticProgress is used.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

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 startAngleDegrees, otherwise an exception would be thrown. By default it equals to 'startAngleDegrees + 360'.

strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH

The stroke width for the progress indicator. The recommended values are CircularProgressIndicatorDefaults.LARGE_STROKE_WIDTH and CircularProgressIndicatorDefaults.SMALL_STROKE_WIDTH.

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 = filledProgressIndicatorColors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator.

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 ExpandedDimensionProp, which is the default, to fill the available space for the best result across different screen sizes. Setting size with a WrappedDimensionProp instance will cause failure and throws an IllegalArgumentException.

Throws
kotlin.IllegalArgumentException

When size is set to be WrappedDimensionProp instance or the provided endAngleDegrees is smaller than the startAngleDegrees.

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.

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 Clickable for click events. When the button is clicked it will fire the associated action.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

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 text with only the text data parameter.

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 icon with the resource ID.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this button. It's highly recommended to set this to expand or weight

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose colors from the same role to ensure accessibility with sufficient color contrast.

horizontalAlignment: Int = if (iconContent != null && labelContent != null) HORIZONTAL_ALIGN_START else HORIZONTAL_ALIGN_CENTER

The horizontal placement of the labelContent and iconContent content. If both are present, this should be HORIZONTAL_ALIGN_START or HORIZONTAL_ALIGN_END (in which case iconContent would be on the start or end side, respectively). Defaults to HORIZONTAL_ALIGN_CENTER if only labelContent or iconContent is present, otherwise it default to HORIZONTAL_ALIGN_START.

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.

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.

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 Clickable for click events. When the card is clicked it will fire the associated action.

graphic: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying graphic data, such as progress indicator.

title: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying the title of the card, expected to be one line of text. Uses CardColors.titleColor color by default.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The optional body content of the card. Uses CardColors.contentColor color by default.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this card. It's highly recommended to set this to expand for the most optimal experience across different screen sizes.

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: CardColors = filledCardColors()

The colors to be used for a background and inner content of this card. Specified colors can be CardDefaults.filledCardColors for high emphasis card, CardDefaults.filledVariantCardColors for high/medium emphasis card, CardDefaults.filledTonalCardColors for low/medium emphasis card, CardDefaults.imageBackgroundCardColors for card with image as a background or custom built CardColors.

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 GraphicDataCardStyle.defaultGraphicDataCardStyle or GraphicDataCardStyle.largeGraphicDataCardStyle.

horizontalAlignment: Int = HORIZONTAL_ALIGN_START

The horizontal placement of the graphic content. This can be either HORIZONTAL_ALIGN_START (when graphic is on the start side), or HORIZONTAL_ALIGN_END (when it is on the end side).

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.

fun MaterialScope.icon(
    protoLayoutResourceId: String,
    size: DimensionBuilders.ImageDimension = defaultIconStyle.size,
    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. Node that, this is not an Android resource id.

size: DimensionBuilders.ImageDimension = defaultIconStyle.size

The side of an icon that will be used for width and height.

tintColor: LayoutColor = defaultIconStyle.tintColor

The color used to tint the icon.

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 used in the buttonGroup to arrange them

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.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 Clickable for click events. When the button is clicked it will fire the associated action.

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 icon with the resource ID.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this button. It's highly recommended to set this to expand or weight

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this button. It's highly recommended to set this to expand or weight

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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.

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:

This card works well in buttonGroup with cards width and height set to expand.

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 Clickable for click events. When the card is clicked it will fire the associated action.

title: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying the title of the card, expected to be one line of text. Uses CardColors.titleColor color by default.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The optional body content of the card. Uses CardColors.contentColor color by default.

secondaryIcon: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

An optional slot for displaying small icon, such as secondaryIcon. Uses CardColors.secondaryIconColor tint color by default.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this card. It's highly recommended to set this to expand or weight for the most optimal experience across different screen sizes.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this card. It's highly recommended to set this to expand for the most optimal experience across different screen sizes.

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

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 CardDefaults.filledCardColors for high emphasis card, CardDefaults.filledVariantCardColors for high/medium emphasis card, CardDefaults.filledTonalCardColors for low/medium emphasis card, CardDefaults.imageBackgroundCardColors for card with image as a background or custom built CardColors.

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 backgroundImage with the content. It can be combined with the specified colors's background color behind it.

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 DataCardStyle.smallDataCardStyle, DataCardStyle.defaultDataCardStyle, DataCardStyle.largeDataCardStyle or DataCardStyle.extraLargeDataCardStyle styles when secondaryIconis present. If it's not present, it's highly recommended to use DataCardStyle.smallCompactDataCardStyle, DataCardStyle.defaultCompactDataCardStyle or DataCardStyle.largeCompactDataCardStyle.

titleContentPlacement: TitleContentPlacementInDataCard = TitleContentPlacementInDataCard.Bottom

The placement of the title and content slots, relative to the given secondaryIcon.

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.

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 text or a single 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.

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 Clickable for click events. When the button is clicked it will fire the associated action.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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 icon with the resource ID.

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.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 Clickable for click events. When the button is clicked it will fire the associated action.

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 backgroundImage with the content. It can be combined with the specified LayoutModifier.background behind it.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription. If LayoutModifier.background modifier is used and the the background image is also specified, the image will be laid out on top of this color. In case of the fully opaque background image, then the background color will not be shown.

width: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp()

The width of this button. It's highly recommended to set this to expand or weight

height: DimensionBuilders.ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp()

The height of this button. It's highly recommended to set this to expand or weight

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.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.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(),
                        )
                    },
                )
            }
        )
    }
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 225dp breakpoint. Some of the examples of content that can be passed in here are: * buttonGroup with buttons or cards * two [buttonGroup * Expanded card

titleSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The app title in the top slot, just below the icon. This should be one line of text with Typography.TITLE_SMALL typography, describing the main purpose of this layout. Title is an optional slot which can be omitted to make space for other elements. Defaults to ColorScheme.onBackground color.

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 textEdgeButton or iconEdgeButton which is designed to have its bottom following the screen's curvature. This bottom slot is optional, if unset the main content will expand more towards the edge of the screen.

labelForBottomSlot: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The label displayed just above the bottomSlot. Default will be one line of text with Typography.TITLE_SMALL typography, ColorScheme.onSurface color that should contain additional description of this layout. When the bottomSlot is not provided or it an edge button, the given label will be ignored.

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: * start and end would be applied as a side margins on mainSlot * bottom would be applied as a bottom margin when bottomSlot is not present.

It is highly recommended to use provided constants for these margins - DEFAULT_PRIMARY_LAYOUT_MARGIN, MIN_PRIMARY_LAYOUT_MARGIN, MID_PRIMARY_LAYOUT_MARGIN or MAX_PRIMARY_LAYOUT_MARGIN, depending on inner content and its corners shape. If providing custom numbers by customizedPrimaryLayoutMargin, it is a requirement for those to be percentages of the screen width and height.

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 = filledProgressIndicatorColors(),
    size: DimensionBuilders.ContainerDimension = expand()
): LayoutElementBuilders.LayoutElement

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, overflow, and start/end transition.

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 is also set, this static value will only be used when the dynamic value cannot be evaluated. By default it equals to 0.

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 staticProgress is used.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

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 startAngleDegrees, otherwise an exception would be thrown. By default it equals to 'startAngleDegrees + 360'.

strokeWidth: @Dimension(unit = 0) Float = LARGE_STROKE_WIDTH

The stroke width for the progress indicator. The recommended values are CircularProgressIndicatorDefaults.LARGE_STROKE_WIDTH and CircularProgressIndicatorDefaults.SMALL_STROKE_WIDTH.

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 = filledProgressIndicatorColors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator.

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 graphicDataCard to have its size as expand, which is the default, to fill the available space for the best result across different screen sizes. Setting size with a WrappedDimensionProp instance will cause failure and throws an IllegalArgumentException.

Throws
kotlin.IllegalArgumentException

When size is set to be WrappedDimensionProp instance or the provided endAngleDegrees is smaller than the startAngleDegrees.

fun MaterialScope.text(
    text: LayoutString,
    typography: Int = defaultTextElementStyle.typography,
    color: LayoutColor = defaultTextElementStyle.color,
    italic: Boolean = defaultTextElementStyle.italic,
    underline: Boolean = defaultTextElementStyle.underline,
    scalable: Boolean = defaultTextElementStyle.scalable,
    maxLines: Int = defaultTextElementStyle.maxLines,
    multilineAlignment: Int = defaultTextElementStyle.multilineAlignment,
    overflow: Int = defaultTextElementStyle.overflow,
    modifiers: LayoutModifier = LayoutModifier
): 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.

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
        )
    }
Parameters
text: LayoutString

The text content for this component.

typography: Int = defaultTextElementStyle.typography

The typography from Typography to be applied to this text. This will have predefined default value specified by each components that uses this text, to achieve the recommended look.

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 getColorProp(token).

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

Whether text should scale with the user font size.

maxLines: Int = defaultTextElementStyle.maxLines

The maximum number of lines that text can occupy.

multilineAlignment: Int = defaultTextElementStyle.multilineAlignment

The horizontal alignment of the multiple lines of text.

overflow: Int = defaultTextElementStyle.overflow

The overflow strategy when text doesn't have enough space to be shown.

modifiers: LayoutModifier = LayoutModifier

Modifiers to set to this element.

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 used in the buttonGroup to arrange them.

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.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 Clickable for click events. When the button is clicked it will fire the associated action.

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 text. This should be small text, usually up to 3 characters text.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this button. It's highly recommended to set this to expand or weight

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this button. It's highly recommended to set this to expand or weight

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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.

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.

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 Clickable for click events. When the card is clicked it will fire the associated action.

title: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying the title of the card, expected to be one line of text. Uses CardColors.titleColor color by default.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The optional body content of the card. Uses CardColors.contentColor color by default.

secondaryText: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

An optional slot for displaying short, secondary text. Uses CardColors.secondaryTextColor color by default.

width: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The width of this card. It's highly recommended to set this to expand or weight for the most optimal experience across different screen sizes.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this card. It's highly recommended to set this to expand for the most optimal experience across different screen sizes.

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

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 CardDefaults.filledCardColors for high emphasis card, CardDefaults.filledVariantCardColors for high/medium emphasis card, CardDefaults.filledTonalCardColors for low/medium emphasis card, CardDefaults.imageBackgroundCardColors for card with image as a background or custom built CardColors.

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 backgroundImage with the content. It can be combined with the specified colors's background color behind it.

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 DataCardStyle.smallDataCardStyle, DataCardStyle.defaultDataCardStyle, DataCardStyle.largeDataCardStyle or DataCardStyle.extraLargeDataCardStyle styles when either icon or secondaryText are present. If they are not present, it's highly recommended to use DataCardStyle.smallCompactDataCardStyle, DataCardStyle.defaultCompactDataCardStyle or DataCardStyle.largeCompactDataCardStyle.

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.

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 or a single 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.

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 Clickable for click events. When the button is clicked it will fire the associated action.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

colors: ButtonColors = filledButtonColors()

The colors used for this button. If not set, ButtonDefaults.filledButtonColors will be used as high emphasis button. Other recommended colors are ButtonDefaults.filledTonalButtonColors and ButtonDefaults.filledVariantButtonColors. If using custom colors, it is important to choose a color pair from same role to ensure accessibility with sufficient color contrast.

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 text with the content.

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.

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 Clickable for click events. When the card is clicked it will fire the associated action.

title: MaterialScope.() -> LayoutElementBuilders.LayoutElement

A slot for displaying the title of the card, expected to be one or two lines of text. Uses CardColors.titleColor color by default.

modifier: LayoutModifier = LayoutModifier

Modifiers to set to this element. It's highly recommended to set a content description using contentDescription.

content: (MaterialScope.() -> LayoutElementBuilders.LayoutElement)? = null

The optional body content of the card. Uses CardColors.contentColor color by default.

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 CardColors.timeColor color by default.

height: DimensionBuilders.ContainerDimension = wrapWithMinTapTargetDimension()

The height of this card. It's highly recommended to set this to expand or weight.

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 Shapes.medium, it is important to adjusts the margins of primaryLayout used to accommodate for more space, for example by using maxPrimaryLayoutMargins. Or, if the shape is set to Shapes.full, using minPrimaryLayoutMargins can be considered.

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 CardDefaults.filledCardColors for high emphasis card, CardDefaults.filledVariantCardColors for high/medium emphasis card, CardDefaults.filledTonalCardColors for low/medium emphasis card, CardDefaults.imageBackgroundCardColors for card with image as a background or custom built CardColors.

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 backgroundImage with the content. It can be combined with the specified colors's background color behind it.

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 title and content. Default to centered when time is not present. When time is present, defaults to start aligned, which is highly recommended.