pekingme 96afc25e5c [Shape] Added missing styles in dev doc.
PiperOrigin-RevId: 743253664
2025-04-07 14:32:27 +00:00

303 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--docs:
title: "Shape Theming"
layout: detail
section: theming
excerpt: "Shape Theming"
iconId: shape
path: /theming/shape/
-->
# Shape theming
Material Design encourages brand expression through shapes. The Material
Components library offers a `shape` library that can be used to create
non-standard shapes using a `MaterialShapeDrawable`, a `Drawable` that can draw
custom shapes while taking shadows, elevation, scale and color into account.
On top of the shape library, the Material Components library provides a
mechanism with which to easily customize component shapes at the theme level.
Shape theming offers a new dimension with which to customize the look and feel
of your app.
## Design and API Documentation
- [Material Design 3 guidelines: Shape](https://m3.material.io/styles/shape/overview)
## How it works
### `MaterialShapeDrawable` and `ShapeAppearanceModel`
`MaterialShapeDrawable` begins with a path generated by a
`ShapeAppearanceModel`. A `ShapeAppearanceModel` is made of `CornerTreatment`s
and `EdgeTreatment`s that combine to create a custom shape path, and is usually
passed to a MaterialShapeDrawable's constructor.
The `shape` library provides some subclassed `CornerTreatment`s and
`EdgeTreatment`s to make it easy to build new shapes:
- [`CutCornerTreatment`](https://developer.android.com/reference/com/google/android/material/shape/CutCornerTreatment)
- [`RoundedCornerTreatment`](https://developer.android.com/reference/com/google/android/material/shape/RoundedCornerTreatment)
- [`TriangleEdgeTreatment`](https://developer.android.com/reference/com/google/android/material/shape/TriangleEdgeTreatment)
Both `CornerTreatment` and `EdgeTreatment` can be subclassed to create custom
corners and edges.
**Note:** When subclassing `CornerTreatment` or `EdgeTreatment`, make sure to
implement the `Cloneable` interface to ensure that the `ShapeAppearanceModel`
can create deep copies of the corner and edge treatments.
### Theming `MaterialShapeDrawable`s
Components backed by `MaterialShapeDrawable`s can use themes across an
application.
#### Shape styles
Style Name | Description | Corner Sizes
------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | ------------
`ShapeAppearance.Material3.Corner.None` | No corners (i.e., fully rectangular) | 0dp
`ShapeAppearance.Material3.Corner.ExtraSmall` | Shape with extra small corner size | 4dp
`ShapeAppearance.Material3.Corner.Small` | Shape with small corner size | 8dp
`ShapeAppearance.Material3.Corner.Medium` | Shape with medium corner size | 12dp
`ShapeAppearance.Material3.Corner.Large` | Shape with large corner size | 16dp
`ShapeAppearance.Material3.Corner.LargeIncreased` | Shape with increased large corner size | 20dp
`ShapeAppearance.Material3.Corner.ExtraLarge` | Shape with extra large corner size | 28dp
`ShapeAppearance.Material3.Corner.ExtraLargeIncreased` | Shape with increased extra large corner size | 32dp
`ShapeAppearance.Material3.Corner.ExtraExtraLarge` | Shape with extra extra large corner size | 48dp
`ShapeAppearance.Material3.Corner.Full` | Shape with full corner size </br> i.e., circle with rounded corners or rhombus with cut corners | 50%
These are the shape styles providing the Material 3 shape scale. The shape
families in these styles (i.e., `cornerFamily`) are mapped to the theme
attribute `?attr/shapeCornerFamily`. See the section below for more details.
#### Shape theme attributes
Theme attributes can be set at the theme level to change the shape values that
components use to set their shapes.
Attribute Name | Description | Default Value
------------------------------------------ | ---------------------------------------------------------------------------------------------- | -------------
`shapeCornerFamily` | The corner family for all shape appearance styles | `rounded`
`shapeAppearanceCornerExtraSmall` | The style reference that contains shape appearance with extra small corners | `ShapeAppearance.Material3.Corner.ExtraSmall`
`shapeAppearanceCornerSmall` | The style reference that contains shape appearance with small corners | `ShapeAppearance.Material3.Corner.Small`
`shapeAppearanceCornerMedium` | The style reference that contains shape appearance with medium corners | `ShapeAppearance.Material3.Corner.Medium`
`shapeAppearanceCornerLarge` | The style reference that contains shape appearance with large corners | `ShapeAppearance.Material3.Corner.Large`
`shapeAppearanceCornerLargeIncreased` | The style reference that contains shape appearance with slightly increased large corners | `ShapeAppearance.Material3.Corner.LargeIncreased`
`shapeAppearanceCornerExtraLarge` | The style reference that contains shape appearance with extra large corners | `ShapeAppearance.Material3.Corner.ExtraLarge`
`shapeAppearanceCornerExtraLargeIncreased` | The style reference that contains shape appearance with slightly increased extra large corners | `ShapeAppearance.Material3.Corner.ExtraLargeIncreased`
`shapeAppearanceCornerExtraExtraLarge` | The style reference that contains shape appearance with extra extra large corners | `ShapeAppearance.Material3.Corner.ExtraExtraLarge`
### Corner family and corner sizes
Shape role | Android attribute | values
--------------------------------- | ---------------------------------- | -------
Corner Family | shapeCornerFamily | Rounded
Corner Size Extra Small | shapeCornerSizeExtraSmall | 4dp
Corner Size Small | shapeCornerSizeSmall | 8dp
Corner Size Medium | shapeCornerSizeMedium | 12dp
Corner Size Large | shapeCornerSizeLarge | 16dp
Corner Size Large Increased | shapeCornerSizeLargeIncreased | 20dp
Corner Size Extra Large | shapeCornerSizeExtraLarge | 28dp
Corner Size Extra Large Increased | shapeCornerSizeExtraLargeIncreased | 32dp
Corner Size Extra Extra Large | shapeCornerSizeExtraExtraLarge | 48dp
Aside from defining these attributes in your theme, you likely will not need to
reference these attributes at all; the widget styles are already mapped to the
appropriate theme attribute to create a seamless shape theming experience. To
change individual shapes throughout your app, you should use the
[shapeAppearance and shapeAppearanceOverlay](#shapeappearance-and-shapeappearanceoverlay-attributes)
attributes rather than redefining theme level attributes.
**Note**: There is no sanity check for the shape values mapped to these theme
attributes. It is the developer's responsibility to guarantee the relative
correctness, for example, "medium" is smaller than "large", etc.
## Usage
### Building a shape appearance
Component shapes are backed by "shape appearances", which are style references
that define aspects of the shape. `ShapeAppearanceModel` uses the
`shapeAppearance` style and creates corner and edge treatments out of the
`shapeAppearance` values.
The following attributes can be used in a `shapeAppearance` style:
Attribute Name | Format | Description | Supported Values
------------------------- |---------------------| ---------------------------------------------------- | ----------------
`cornerFamily` | enum | corner family to be used for all four corners | `rounded`, `cut`
`cornerFamilyTopLeft` | enum | corner family to be used for the top left corner | `rounded`, `cut`
`cornerFamilyTopRight` | enum | corner family to be used for the top right corner | `rounded`, `cut`
`cornerFamilyBottomRight` | enum | corner family to be used for the bottom right corner | `rounded`, `cut`
`cornerFamilyBottomLeft` | enum | corner family to be used for the bottom left corner | `rounded`, `cut`
`cornerSize` | dimension\|fraction | corner size to be used for all four corners | dimension values, percentage
`cornerSizeTopLeft` | dimension\|fraction | corner size to be used for the top left corner | dimension values, percentage
`cornerSizeTopRight` | dimension\|fraction | corner size to be used for the top right corner | dimension values, percentage
`cornerSizeBottomRight` | dimension\|fraction | corner size to be used for the bottom right corner | dimension values, percentage
`cornerSizeBottomLeft` | dimension\|fraction | corner size to be used for the bottom left corner | dimension values, percentage
To build a `shapeAppearance`, you need at least a **`cornerSize`** and
**`cornerFamily`** value specified for each corner.
#### `ShapeAppearance` and `shapeAppearanceOverlay` attributes
Two attributes are provided to set a component's shape style, `shapeAppearance`
and `shapeAppearanceOverlay`:
Attribute Name | Description
------------------------ | --------------------------------------
`shapeAppearance` | Style reference that contains shape values that are used to style the component. Should point to a theme attribute style reference such as `?attr/shapeAppearanceCornerExtraSmall`.
`shapeAppearanceOverlay` | Style reference that contains shape values that layer on top of a `shapeAppearance` style. This attribute is intended for overrides on top of the themed shapeAppearance shape values, and should map to a custom style reference rather than a themed style reference.
The `shapeAppearanceOverlay` attribute is provided to override components on a
case by case basis. This attribute stacks on top of the `shapeAppearance`
attribute; the `shapeAppearance` is read first, and then if there is anything
specified in the `shapeAppearanceOverlay` attribute, it overrides whats set in
the `shapeAppearance`.
**Note:** `shapeAppearance` styles require both `cornerSize` and `cornerFamily`
to be set, while `shapeAppearanceOverlay` does not. This means that when
defining a custom `shapeAppearance` style, you should either inherit from a
parent if one exists, or set both `cornerSize` and `cornerFamily`. However, when
defining a style to be used as a `shapeAppearanceOverlay`, you should generally
set an empty parent by setting `parent=""`. This is because
`shapeAppearanceOverlay` stacks on top of `shapeAppearance`, so all values will
be set in the `shapeAppearance.`
### Using `shapeAppearance` in the theme
The Material Components library supports theming shapes at the application
level. To apply theme shapes across your app, specify the shape theme attributes
in your theme. This will allow
[components that support shape theming](#supported-components) to read the
customized values and change their shapes accordingly.
If you want to change the small and medium corners in your app to cut corners,
define the shape theme attributes to point to custom style references that
contain shape values:
```xml
<style name="Theme.MyApp" parent="Theme.Material3.Light">
...
<item name="shapeAppearanceCornerSmall">@style/ShapeAppearance.MyApp.Corner.Small</item>
<item name="shapeAppearanceCornerMedium">@style/ShapeAppearance.MyApp.Corner.Medium</item>
...
</style>
```
The shape theme attributes should point to custom `shapeAppearance` styles that
define both `cornerSize` and `cornerFamily`. You can either define both
attributes in a style from scratch or modify the corner family from a built-in
shape style like this:
```xml
<style name="ShapeAppearance.MyApp.Corner.Small" parent="">
<item name="cornerFamily">cut</item>
<item name="cornerSize">4dp</item>
</style>
<style name="ShapeAppearance.MyApp.Corner.Medium" parent="ShapeAppearance.Material3.Corner.Medium">
<item name="cornerFamily">cut</item>
<item name="cornerSize">8dp</item>
</style>
```
Material components that support shape theming use theme attributes according to
the themed shape values.
### Customizing component shapes
#### Theme-wide component overrides
You can change a component's shape across the entire app by defining a custom
`shapeAppearanceOverlay` in the component's style.
If you want to modify `MaterialCardView` so that it uses 16dp rounded corners
across the entire app, define your own card style to extend from the widget's
style, and set the relevant attributes to the desired theme attributes:
```xml
<style name="Widget.MyApp.CardView" parent="Widget.Material3.CardView">
<item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay.MyApp.CardView</item>
</style>
```
And define `ShapeAppearanceOverlay.MyApp.CardView`:
```xml
<style name="ShapeAppearanceOverlay.MyApp.CardView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">16dp</item>
</style>
```
Then make sure to set the component's style in your theme to your custom style:
```xml
<style name="Theme.MyApp" parent="Theme.Material3.Light">
...
<item name="materialCardViewStyle">@style/Widget.MyApp.CardView</item>
...
</style>
```
All cards in your app should now have 16dp rounded corners.
#### Individual component overrides
You can also change an individual component's shape on a case by case basis. For
example, if cards in your theme have 16dp rounded corners, but one card should
have 16dp cut corners, you can change that card's `cornerFamily` by setting the
`shapeAppearanceOverlay` attribute on the card in your layout.
Define a custom `shapeAppearanceOverlay` style with just the attribute you want
to overlay on top of the existing `shapeAppearance`. In this case, you would set
`cornerFamily` to `cut`:
```xml
<style name="ShapeAppearanceOverlay.MyApp.CardView.Cut" parent="">
<item name="cornerFamily">cut</item>
</style>
```
Then, set the card's `shapeAppearanceOverlay` attribute to that
`ShapeAppearanceOverlay` style in your layout:
```xml
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/mtrl_card_spacing"
android:layout_marginTop="@dimen/mtrl_card_spacing"
android:layout_marginRight="@dimen/mtrl_card_spacing"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.MyApp.CardView.Cut">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/card_text"/>
</com.google.android.material.card.MaterialCardView>
```
The `cornerFamily` attribute set in the `shapeAppearanceOverlay` will override
the `cornerFamily` set in the card's `shapeAppearance`, so the card should now
have 16dp cut corners instead of 16dp rounded corners.
#### Supported components
Components that support shape theming have a `shapeAppearance` attribute, a
`shapeAppearanceOverlay` attribute, and are backed by a `MaterialShapeDrawable`:
* [Bottom Sheet](../components/BottomSheet.md)
* [Card](../components/Card.md)
* [Chip](../components/Chip.md)
* [Date Picker](../components/DatePicker.md)
* [Dialog](../components/Dialog.md)
* [Extended Floating Action Button](../components/FloatingActionButton.md?#extended-fabs)
* [Floating Action Button](../components/FloatingActionButton.md)
* [Button](../components/Button.md)
* [Time Picker](../components/TimePicker.md)
* [Navigation Drawer](../components/NavigationDrawer.md)
* [Slider](../components/Slider.md)
* [Snackbar](../components/Snackbar.md)
* [Text Field](../components/TextField.md)