Create delightful Wear OS Widgets using sample tile layouts

Create delightful Wear OS Widgets using sample tile layouts

Home » News » Create delightful Wear OS Widgets using sample tile layouts
Table of Contents

Posted by Michael Stillwell Developer Relations Engineer

Golden Tile Templates

Golden Tile Templates

This publish is a part of Put on OS Highlight Week. Right now, we’re specializing in creating partaking Put on OS tiles with new assets and up to date design steering.

Put on OS is all about offering customers with the proper data on the proper time. Whereas a full app is nice for immersive experiences, generally customers simply want a fast look at data or a easy strategy to take motion.

Tiles are quick, predictable surfaces that customers can entry with a easy swipe from their watch face. They’re designed for fast, frequent duties like checking the climate, beginning a timer, or monitoring health objectives.

To streamline your workflow from idea to launch, we’re happy to announce a set of assets that can assist you construct lovely and efficient tiles utilizing the Materials 3 Expressive design system.

These layouts are an evolution of a earlier model based mostly on Materials 2.5, now up to date to Materials 3 Expressive to create a contemporary, premium really feel that makes your tile a extra cohesive a part of the Put on OS.

Material 2.5 and Material 3 Expressive side by side version comparison of goal, media, and ski tiles

Materials 2.5 and Materials 3 Expressive variations of the “Objective”, “Media”, and “Ski” tiles

We hope these assets function inspiration and a sensible place to begin, whether or not you are new to Put on OS growth or trying so as to add a tile to your present app.

Get began with pattern layouts

Tiles are constructed declaratively utilizing the ProtoLayout library. Materials 3 Expressive’s Main Structure is organized round a slot-based structure. Operating from high to backside, these slots are:

    • An optionally available titleSlot for a header.
    • A compulsory mainSlot in your core content material.
    • An optionally available bottomSlot for supplemental actions.

Your app implements a TileService, which returns a structure when requested by the system. This structure is then used to construct and render the tile. Discover ways to get began with tiles.

For instance, this is the “Objective” structure for visualizing step rely. The titleSlot incorporates the “Steps” textual content, the mainSlot holds the graphic information card with a progress ring and step information, and the bottomSlot options the “Monitor” edge-hugging button. (The icon that seems on the high of the tile is laid out in your app’s manifest is and drawn by the system.)

Daily steps goal tile on a round watch face

Day by day steps objective tile

The code for this structure is structured logically round these slots:

enjoyable structure(
    context: Context,
    deviceParameters: DeviceParameters,
    steps: Int,
    objective: Int
) =
    materialScope(
        context = context,
        deviceConfiguration = deviceParameters
    ) {
        val stepsString = NumberFormat.getNumberInstance().format(steps)
        val goalString = NumberFormat.getNumberInstance().format(objective)
        primaryLayout(
            titleSlot = { textual content("Steps".layoutString) },
            // Modify margins to create more room when utilizing absolutely rounded corners
            margins = PrimaryLayoutMargins.MIN_PRIMARY_LAYOUT_MARGIN,
            mainSlot = {
                graphicDataCard(
                    onClick = clickable(),
                    peak = broaden(),
                    colours = filledTonalCardColors(),
                    title = { textual content(stepsString.layoutString) },
                    content material = { textual content("of $goalString".layoutString) },
                    horizontalAlignment = LayoutElementBuilders.HORIZONTAL_ALIGN_END,
                    graphic = {
                        constructGraphic(
                            mainContent = {
                                circularProgressIndicator(
                                    staticProgress = 1F * steps / objective,
                                    // On supported gadgets, animate the arc
                                    dynamicProgress =
                                    DynamicFloat.onCondition(
                                        PlatformEventSources.isLayoutVisible()
                                    )
                                        .use(1F * information.steps / information.objective)
                                        .elseUse(0F)
                                        .animate(
                                            CircularProgressIndicatorDefaults
                                                .recommendedAnimationSpec
                                        ),
                                    startAngleDegrees = 200F,
                                    endAngleDegrees = 520F,
                                )
                            },
                            iconContent = { icon(ICON_ID) },
                        )
                    },
                )
            },
            bottomSlot = {
                textEdgeButton(onClick = clickable()) { textual content("Monitor".layoutString) }
            },
        )
    }

With this easy operate, you get a great-looking, responsive tile. The ProtoLayout Material3 library handles the heavy lifting, equivalent to setting margins to keep away from clipping on spherical screens and guaranteeing parts adapt easily to completely different show sizes.

Create customized tile layouts

Whereas our layouts cowl many widespread use circumstances, you may generally want a singular structure. The Materials 3 Expressive parts present a versatile basis for constructing customized designs.

To translate designs into code, begin with essentially the most visually comparable structure and modify it. The next sections clarify easy methods to modify an present structure slot by slot.

Customise the title and backside slots

The titleSlot is commonly a textual content() ingredient. To confirm that the faucet targets of the opposite components are interactive, you might want to disguise the title slot on smaller gadgets. Discover ways to develop tiles for various display screen sizes.

primaryLayout(
    titleSlot =
        if (isLargeScreen()) {
            { textual content("$tasksLeft conscious duties left".layoutString) }
        } else {
            null
        },
    // ...
)

The bottomSlot offers customers with a main motion, sometimes an EdgeButton. You should utilize a textEdgeButton() for a descriptive motion. Alternatively, you need to use an icon equivalent to + through the use of an iconEdgeButton.

Utilizing an icon is a two-step course of:

  1. Outline the iconEdgeButton in your structure, giving your icon a singular useful resource ID string:
  2. primaryLayout(
        // ...
        bottomSlot = {
            iconEdgeButton(
                onClick = clickable(),
                modifier = LayoutModifier.contentDescription("Add occasion"),
                iconContent = { icon("icon_plus_id") }
            )
        }
    )
    

  3. Present the precise drawable useful resource in onTileResourcesRequest():
  4. override enjoyable onTileResourcesRequest(
        requestParams: RequestBuilders.ResourcesRequest
    ) =
        Futures.immediateFuture(
            ResourceBuilders.Sources.Builder()
                .setVersion(requestParams.model)
                .addIdToImageMapping(
                    "plus_icon_id",
                    ResourceBuilders.ImageResource.Builder()
                        .setAndroidResourceByResId(
                            ResourceBuilders.AndroidImageResourceByResId.Builder()
                                .setResourceId(R.drawable.outline_add_2_24)
                                .construct()
                        )
                        .construct()
                )
                .construct()
        )
    

See Alarm.kt for a full code pattern demonstrating this method.

Customise the principle slot

The mainSlot is the place the core content material of your tile lives and the place essentially the most vital customization happens. Let’s stroll by a number of examples.

Case research: Exercise tile

example of a compact workout tile on a round watch face

A compact exercise tile for smaller Put on OS gadgets.

example of an expanded workout tile on a round watch face

An expanded exercise tile offering extra data on bigger screens.

This tile must adapt its structure for various display screen sizes. For the smaller structure, three easy iconButton parts are an ideal match. Within the bigger structure, the central button shows extra information (period, unit, and an icon). Despite the fact that it is semantically nonetheless a button, on this case the iconDataCard ingredient is a greater match. It is particularly designed to show a number of items of information, and we will simply alter its width and peak.

iconDataCard(
    title = { textual content("30".layoutString, typography = DISPLAY_MEDIUM) },
    content material = { textual content("Minutes".layoutString, typography = TITLE_MEDIUM) },
    secondaryIcon = { icon("icon_run_id") },
    form = shapes.massive, // alter the nook form
    onClick = clickable(),
    // make ingredient extra distinguished on bigger screens
    width = if (isLargeScreen()) weight(1.5f) else broaden(),
    peak = broaden(),
    // ...
)

See Exercise.kt for the total supply code.

Case research: Snowboarding stats tile

example of a custom skiing tile on a round watch face

A customized tile for snowboarding stats

The design for this tile is constructed round a pill-shaped ingredient that shows three traces of textual content, every with distinctive typography. A textDataCard() is ideal for this, providing slots for a “title” (the metric), “content material” (the worth), and “secondaryText” (the models). These slots include default styling that you would be able to override to match your design exactly.

enjoyable MaterialScope.statTextButton(stat: Stat) =
    textDataCard(
        onClick = clickable(),
        width = broaden(),
        peak = broaden(),
        form = shapes.extraLarge,
        title = {
            textual content(
                stat.worth.layoutString,
                typography =
                    if (isLargeScreen()) {
                        Typography.NUMERAL_SMALL
                    } else {
                        Typography.NUMERAL_EXTRA_SMALL
                    }
            )
        },
        content material = {
            textual content(
                stat.unit.layoutString,
                typography =
                    if (isLargeScreen()) {
                        Typography.TITLE_MEDIUM
                    } else {
                        Typography.TITLE_SMALL
                    }
            )
        },
        secondaryText = {
            textual content(
                stat.label.layoutString,
                typography =
                    if (isLargeScreen()) {
                        Typography.TITLE_MEDIUM
                    } else {
                        Typography.TITLE_SMALL
                    }
            )
        }
    )

Discover how the typography constants are diverse in keeping with the display screen measurement (TITLE_MEDIUM vs. TITLE_SMALL, for instance). Given the number of display screen and font sizes on Put on OS, it is a key method to maintain textual content legible. As an alternative of making an attempt to manually tweak your structure for each potential mixture, concentrate on adjusting the typography through the use of completely different font measurement constants.

For a constant look, attempt to stick with the identical “class” of typography fixed, equivalent to BODY_MEDIUM on small screens and BODY_LARGE on bigger ones. Keep away from leaping between completely different classes, like from LABEL_LARGE to DISPLAY_SMALL, as these constants can range in additional than simply measurement, affecting font weight and different visible properties.

See Ski.kt for the total supply code.

One other method to adapting a structure to completely different display screen sizes is solely so as to add or take away components relying on the show measurement, as demonstrated by the Climate.kt structure. Whereas each variations show the identical present situations, the bigger model provides extra data to the forecast.

example of a glanceable weatehr tile on a round watch face

A glanceable climate tile for smaller Put on OS screens

example of an expanded weather tile on a round watch face

An enhanced climate tile with forecast particulars for bigger shows.

Customise colours

You would possibly discover that the templates do not specify a colour scheme, but they adapt to the consumer’s chosen theme on Put on OS 6. This is because of dynamic theming, a system function that robotically generates a colour scheme by extracting seed colours from sources just like the consumer’s watch face. For tiles, that is the default conduct.

examples of the same weather app featuring three different system-generated color themes

The identical Climate tile beneath three completely different system-generated colour themes

As a developer, this provides you two most important choices in your tile’s look:

Possibility 1 (really useful): Comply with dynamic colour theming. A dynamic theme is utilized by default. On this case, you must present a defaultColorScheme for use as a fallback if the consumer disables dynamic theming or if the gadget does not help it. This method creates a constant and cohesive really feel, permitting your tile to combine seamlessly with the system.

val myColorScheme =
    ColorScheme(
        main = ...
        onPrimary = ...
        // 27 extra
    )

materialScope(
  defaultColorScheme = myColorScheme
) {
  // If the consumer selects "no theme" in settings, myColorScheme is used.
  // In any other case, the system-provided theme is used.
}

Possibility 2: Use your model colours. To make sure model consistency, you may pressure your tile to at all times use your customized colour scheme by setting allowDynamicTheme to false. On this case, the identical colours will at all times be used, no matter the consumer’s chosen colour theme.

materialScope(
  allowDynamicTheme = false,
  defaultColorScheme = myColorScheme
) {
  // myColorScheme is *at all times* used.
}

See Theming for extra data on the theming system.

Develop and debug

To hurry up your growth cycle, Put on OS offers a number of instruments that can assist you debug and check your tiles straight in Android Studio and on the command line.

Dive in and begin constructing

These assets are designed to make constructing high-quality Put on OS tiles simpler and extra inspiring. We won’t wait to see what you create with them.

Discover the layouts and get began right this moment by testing the Figma design equipment or the code on GitHub.

Supply hyperlink

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 

share this article.

Enjoying my articles?

Sign up to get new content delivered straight to your inbox.

Please enable JavaScript in your browser to complete this form.
Name