PrimaryLayoutKt

Added in 1.3.0

public final class PrimaryLayoutKt


Summary

Public methods

static final @NonNull 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.

Public methods

public static final @NonNull LayoutElementBuilders.LayoutElement primaryLayout(
    @NonNull MaterialScope receiver,
    @NonNull Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> mainSlot,
    Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> titleSlot,
    Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> bottomSlot,
    Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> labelForBottomSlot,
    ModifiersBuilders.Clickable onClick,
    @NonNull PrimaryLayoutMargins margins
)

ProtoLayout Material3 full screen layout that represents a suggested Material3 layout style that is responsive and takes care of the elements placement, together with the recommended margin and padding applied.

This layout is meant to occupy the whole screen, so nothing else should be added on top of it.

On the top, there is an icon that will be automatically placed by the system, followed by the optional title slot. The icon slot needs to be reserved for the whole ProtoLayout Layout and no other content should be added at the top of the screen as it will be overlapped with the system placed icon.

At the bottom, there is an optional fixed slot for either {@link EdgeButton} as a main action or small non tappable content.

The middle of the layout is main content, that will fill the available space. For the best results across different screen sizes, it's recommended that this content's dimension are also DimensionBuilders.expand or DimensionBuilders.weight. Additional content in the main one can be added after a 225dp breakpoint.

import androidx.wear.protolayout.LayoutElementBuilders import androidx.wear.protolayout.LayoutElementBuilders.Box import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement import androidx.wear.protolayout.ModifiersBuilders import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconEdgeButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) {  primaryLayout(  titleSlot = { text("App title".layoutString) },  mainSlot = {  buttonGroup {  // To be populated with proper components  buttonGroupItem {  LayoutElementBuilders.Box.Builder()  .setModifiers(  ModifiersBuilders.Modifiers.Builder()  .setBackground(  ModifiersBuilders.Background.Builder()  .setCorner(shapes.small)  .build()  )  .build()  )  .build()  }  }  },  // Adjust margins as the corner of the inner content is on the square side.  margins = MAX_PRIMARY_LAYOUT_MARGIN,  bottomSlot = {  iconEdgeButton(  onClick = clickable,  modifier = LayoutModifier.contentDescription("Description")  ) {  icon("id")  }  }  )  }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.backgroundImage import androidx.wear.protolayout.material3.card import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) {  primaryLayout(  mainSlot = {  card(  onClick = clickable,  modifier =  LayoutModifier.contentDescription("Card with image background")  .clickable(id = "card"),  width = expand(),  height = expand(),  backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }  ) {  text("Content of the Card!".layoutString)  }  }  )  }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.button import androidx.wear.protolayout.material3.buttonGroup import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.iconButton import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.material3.textButton import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.background import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) {  primaryLayout(  mainSlot = {  buttonGroup {  buttonGroupItem {  iconButton(  onClick = clickable,  modifier =  LayoutModifier.contentDescription(  "Big button with image background"  ),  width = expand(),  height = expand(),  iconContent = { icon("id1") }  )  }  buttonGroupItem {  iconButton(  onClick = clickable,  modifier =  LayoutModifier.contentDescription(  "Big button with image background"  ),  width = expand(),  height = expand(),  shape = shapes.large,  iconContent = { icon("id2") }  )  }  buttonGroupItem {  textButton(  onClick = clickable,  modifier =  LayoutModifier.contentDescription(  "Big button with image background"  ),  width = expand(),  height = expand(),  shape = shapes.large,  labelContent = { text("Dec".layoutString) }  )  }  }  }  )  }
import androidx.wear.protolayout.DimensionBuilders.expand import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledTonalProgressIndicatorColors import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.largeGraphicDataCardStyle import androidx.wear.protolayout.material3.graphicDataCard import androidx.wear.protolayout.material3.icon import androidx.wear.protolayout.material3.materialScope import androidx.wear.protolayout.material3.primaryLayout import androidx.wear.protolayout.material3.segmentedCircularProgressIndicator import androidx.wear.protolayout.material3.text import androidx.wear.protolayout.modifiers.LayoutModifier import androidx.wear.protolayout.modifiers.clickable import androidx.wear.protolayout.modifiers.contentDescription import androidx.wear.protolayout.types.layoutString materialScope(context, deviceConfiguration) {  primaryLayout(  mainSlot = {  graphicDataCard(  onClick = clickable,  modifier = LayoutModifier.contentDescription("Data Card with graphic"),  height = expand(),  colors = filledVariantCardColors(),  style = largeGraphicDataCardStyle(),  title = { text("1,234".layoutString) },  content = { icon("steps") },  graphic = {  segmentedCircularProgressIndicator(  segmentCount = 5,  staticProgress = 0.5F,  colors = filledTonalProgressIndicatorColors(),  )  },  )  }  )  }
Parameters
@NonNull Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> mainSlot

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

Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> titleSlot

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. When this titleSlot is text, it is considered as important for accessibility by default, and is marked as heading role, which can be overridden by adding LayoutModifier.clearSemantics into the text modifier.

Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> bottomSlot

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. When this bottomSlot is text, it is considered as important for accessibility by default, which can be overridden by adding LayoutModifier.clearSemantics into the text modifiers.

Function1<@NonNull MaterialScope, @NonNull LayoutElementBuilders.LayoutElement> labelForBottomSlot

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. When this labelForBottomSlot is text, it is considered as important for accessibility by default, which can be overridden by adding LayoutModifier.clearSemantics into the text modifiers.

ModifiersBuilders.Clickable onClick

The clickable action for whole layout. If any area (outside of other added tappable components) is clicked, it will fire the associated action.

@NonNull PrimaryLayoutMargins margins

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.