Card Skeleton
A PantrixCard whose content has not arrived: the card's own surface, with bars where its header, its body and its actions will be.
import com.pantrixui.components.container.card.PantrixCardSkeleton
- Three variants.
variantsays how the card is set apart from what it stands on:Elevatedby a shadow,Filledby a fill,Outlinedby a hairline. - Slots.
headerstands above the body andfooterbelow it;mediais drawn above them all, edge to edge, and takes none of the card's padding. The lines of the body have the theme's small spacing (spacing.sm) between them. - Height. A card given a height is filled by its body: the
footerstands at the card's foot, and a child of the body given aweighttakes the room between. The cards of a row are of one height this way. - One button. Given
onClick, the whole card is one button: a screen reader hears one target. A button in thefooterkeeps its own press. - A card that cannot be pressed. A card that has
onClickand whoseenabledis false gives its content the theme's disabled colour; a child that sets a colour of its own keeps it. - Content colour. On the theme's
surface, that is, in anElevatedand anOutlinedcard, the card gives its content no colour: each child is drawn in its own default. AFilledcard, and a card given a role's fill, gives the colour that reads on that fill. - Colours of its own.
CardColorsgives the fill, the content's colour and the edge; one that is left out stays the variant's. - Platform. The corners and the shadow depend on the platform (
CardStyle): a medium corner and a 2dp shadow on Android, a large corner and no shadow on iOS, a small corner and a 1dp shadow on desktop and the web. - Skeleton.
PantrixCardSkeletonstands in for a card whose data has not arrived: the card's own surface, with bars in it where the header, the lines and the buttons will be. It is announced to a screen reader once, for the whole card. - Automation.
tagKeygives the card the tagCard_<tagKey>; a press is reported as aCardevent, along with the card's variant.
Examples
Until the data arrives: the skeleton
Press "Refresh": for two seconds the two cards are replaced by their skeletons. PantrixCardSkeleton is not drawn to look like a card: it is built from the card's own shape, fill, shadow, padding and spacing. Its bars take the room of what they stand in for: when the data arrives the card's height does not change, and nothing below it moves.
The skeleton cannot know what is in the card: showHeader, lines, footerButtons and mediaHeight are given to match the card it stands in for. The first card has a header, one line and two buttons: lines = 1, footerButtons = 2.
The fill and the content colour of the "Campaign" card were given by the caller. Its skeleton takes the card's colours with colors too; its bars are drawn in the colour given with skeletonColors.
val own = ownColors()
val campaign = CardColors(container = own.container, content = own.onContainer)
var loading by remember { mutableStateOf(false) }
LaunchedEffect(loading) {
if (loading) {
delay(2_000)
loading = false
}
}
if (loading) {
PantrixCardSkeleton(modifier = Modifier.fillMaxWidth(), lines = 1, footerButtons = 2)
} else {
PantrixCard(
modifier = Modifier.fillMaxWidth(),
header = {
PantrixText(
text = "Order #1042",
style = PantrixTheme.typography.title,
role = TextRole.Heading(level = 3)
)
},
footer = {
PantrixButton(
text = "Refresh",
onClick = { loading = true },
variant = ButtonVariant.Text,
tagKey = "reload"
)
PantrixButton(text = "Track", onClick = {}, tagKey = "track")
}
) {
PantrixText(text = "Two items, delivery on Thursday")
}
}
if (loading) {
PantrixCardSkeleton(
modifier = Modifier.fillMaxWidth(),
variant = CardVariant.Filled,
colors = campaign,
skeletonColors = SkeletonColors(base = own.onContainer.copy(alpha = 0.3f), highlight = own.container),
lines = 1
)
} else {
PantrixCard(
modifier = Modifier.fillMaxWidth(),
variant = CardVariant.Filled,
colors = campaign,
tagKey = "campaign"
) {
PantrixText(text = "Campaign", style = PantrixTheme.typography.title)
PantrixText(text = "Its fill and content colour were given by the caller")
}
}
A loading list
A loading list: the skeletons of two outlined cards. mediaHeight stands in for the media the card will show, lines for the lines of the body, and footerButtons for the actions.
A skeleton that stands alone is announced to a screen reader once, for the whole card: with the theme's word, "Loading". Inside something that already says it is loading, this announcement is turned off: here the list says once that it is loading, and the skeletons were given contentDescription = null.
val loading = PantrixTheme.strings.loading
Column(
modifier = Modifier.widthIn(max = 360.dp).semantics { contentDescription = loading },
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
) {
repeat(2) {
PantrixCardSkeleton(
modifier = Modifier.fillMaxWidth(),
variant = CardVariant.Outlined,
lines = 2,
footerButtons = 1,
mediaHeight = 96.dp,
contentDescription = null
)
}
}
API
modifier
A PantrixCard whose content has not arrived: the card's own surface, with bars where its header, its body and its actions will be.
| Parameter | Type | Default | What it is |
|---|---|---|---|
modifier | Modifier | Modifier | the skeleton's modifier. |
variant | CardVariant | CardVariant.Elevated | the variant of the card it replaces: the same fill, shadow and edge. |
style | CardStyle? | null | this call's own CardStyle: over every enclosing one and under the density. The footer's bars keep the theme's button shape. |
shape | Shape | PantrixTheme.style(CardStyle, style).shape.toShape() | the card's corners: by default the resolved style's. Given here, it wins over style's. |
colors | CardColors? | null | the colours of the card it replaces, where that card has its own: the same fill and edge. |
skeletonColors | SkeletonColors? | null | the bars' own colours, where they are not the theme's. |
contentPadding | PaddingValues | PaddingValues(PantrixTheme.spacing.lg) | the room around the bars, as around a card's content. |
showHeader | Boolean | true | whether a bar stands in for the header: a line of the theme's title. |
lines | Int | 3 | how many lines of text the bars stand in for, in the type a PantrixText has by itself. |
footerButtons | Int | 0 | how many buttons the footer's bars stand in for. |
mediaHeight | Dp? | null | the height of the media the card will show above its content, or null for a card without any. |
contentDescription | String? | PantrixTheme.strings.loading | what a screen reader says for the whole skeleton, or null inside something that already says it is loading. |
tagKey | String? | null | the skeleton's automation key: it is CardSkeleton_<tagKey>, and its bars have no tags of their own. Without one it has no tag. |
CardStyle
PantrixCard's geometry: its corners, and the shadow of its elevated variant.
| Parameter | Type | Default | What it is |
|---|---|---|---|
shape | ShapeSpec | ShapeSpec.Unspecified | The card's corners: medium on Android, large on iOS, small on desktop and the web. |
elevation | Dp | Dp.Unspecified | The shadow under CardVariant.Elevated: 2dp on Android, none on iOS, 1dp on desktop and the web. The other variants draw none. |
CardColors
What PantrixCard is painted with, for a card that does not take its variant's colours: a colour that is set is used, and one that is left out stays the variant's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
container | Color | Color.Unspecified | The card's fill. The theme's surface, or the neutral role's container in a CardVariant.Filled card. |
content | Color | Color.Unspecified | What the card holds is drawn in, unless a child sets a colour of its own: the colour that reads on container. None on the theme's surface, where each child draws in its own default, a text in textPrimary; the neutral role's onContainer in a filled card. |
border | Color | Color.Unspecified | The hairline around the card. The theme's divider on a CardVariant.Outlined card, and where that card is given a fill that is no ground of the theme's, on which that line would not read, a share of what is written there: the edge a subtle button has. The other variants have none unless one is given here. |