Files
VibeCoding/.agents/skills/display-glasses-with-jetpack-compose-glimmer/references/listitem-source.md

281 lines
12 KiB
Markdown

When creating a Glimmer Icon Sizes component, refer to the following source
code in `ListItem.kt` for list items:
```kotlin
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.xr.glimmer
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp
/**
* ListItem is a component used to represent a single item in a
* [androidx.xr.glimmer.list.GlimmerLazyColumn]. A ListItem has a primary label [content], and may
* also have any combination of [supportingLabel], [leadingIcon], and [trailingIcon]. The supporting
* label is displayed below the primary label and can be used to provide additional information. A
* ListItem fills the maximum width available by default.
*
* This ListItem is focusable - see the other [ListItem] overload for a clickable ListItem.
*
* A simple ListItem with just a primary label:
*
* @sample androidx.xr.glimmer.samples.ListItemSample
*
* A ListItem with a primary and supporting label:
*
* @sample androidx.xr.glimmer.samples.ListItemWithSupportingLabelSample
*
* A ListItem with a primary label, a supporting label, and a leading icon:
*
* @sample androidx.xr.glimmer.samples.ListItemWithSupportingLabelAndLeadingIconSample
* @param modifier the [Modifier] to be applied to this list item
* @param supportingLabel optional supporting label to be placed underneath the primary label
* [content]
* @param leadingIcon optional leading icon to be placed before the primary label [content]. This is
* typically an [Icon] tinted with [contentColor] by default.
* @param trailingIcon optional trailing icon to be placed after the primary label [content]. This
* is typically an [Icon] tinted with [contentColor] by default.
* @param shape the [Shape] used to clip this list item, and also used to draw the background and
* border
* @param color background color of this list item
* @param contentColor content color used by components inside [content], [supportingLabel],
* [leadingIcon], and [trailingIcon].
* @param border the border to draw around this list item
* @param contentPadding the spacing values to apply internally between the container and the
* content
* @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
* emitting Interactions for this list item. You can use this to change the list item's appearance
* or preview the list item in different states. Note that if `null` is provided, interactions
* will still happen internally.
* @param content the main content / primary label to display inside this list item
*/
@Composable
public fun ListItem(
modifier: Modifier = Modifier,
supportingLabel: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = GlimmerTheme.shapes.medium,
color: Color = GlimmerTheme.colors.surface,
contentColor: Color = calculateContentColor(color),
border: BorderStroke? = SurfaceDefaults.border(),
contentPadding: PaddingValues = ListItemDefaults.contentPadding,
interactionSource: MutableInteractionSource? = null,
content: @Composable () -> Unit,
) {
ListItemImpl(
modifier = modifier,
onClick = null,
supportingLabel = supportingLabel,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
shape = shape,
color = color,
contentColor = contentColor,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
}
/**
* ListItem is a component used to represent a single item in a
* [androidx.xr.glimmer.list.GlimmerLazyColumn]. A ListItem has a primary label [content], and may
* also have any combination of [supportingLabel], [leadingIcon], and [trailingIcon]. The supporting
* label is displayed below the primary label and can be used to provide additional information. A
* ListItem fills the maximum width available by default.
*
* This ListItem is focusable and clickable - see the other [ListItem] overload for a ListItem that
* is only focusable.
*
* A simple clickable ListItem with just a primary label:
*
* @sample androidx.xr.glimmer.samples.ClickableListItemSample
*
* A clickable ListItem with a primary and supporting label:
*
* @sample androidx.xr.glimmer.samples.ClickableListItemWithSupportingLabelSample
*
* A clickable ListItem with a primary label, a supporting label, and a leading icon:
*
* @sample androidx.xr.glimmer.samples.ClickableListItemWithSupportingLabelAndLeadingIconSample
* @param onClick called when this list item is clicked
* @param modifier the [Modifier] to be applied to this list item
* @param supportingLabel optional supporting label to be placed underneath the primary label
* [content]
* @param leadingIcon optional leading icon to be placed before the primary label [content]. This is
* typically an [Icon] tinted with [contentColor] by default.
* @param trailingIcon optional trailing icon to be placed after the primary label [content]. This
* is typically an [Icon] tinted with [contentColor] by default.
* @param shape the [Shape] used to clip this list item, and also used to draw the background and
* border
* @param color background color of this list item
* @param contentColor content color used by components inside [content], [supportingLabel],
* [leadingIcon], and [trailingIcon].
* @param border the border to draw around this list item
* @param contentPadding the spacing values to apply internally between the container and the
* content
* @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
* emitting Interactions for this list item. You can use this to change the list item's appearance
* or preview the list item in different states. Note that if `null` is provided, interactions
* will still happen internally.
* @param content the main content / primary label to display inside this list item
*/
@Composable
public fun ListItem(
onClick: () -> Unit,
modifier: Modifier = Modifier,
supportingLabel: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = GlimmerTheme.shapes.medium,
color: Color = GlimmerTheme.colors.surface,
contentColor: Color = calculateContentColor(color),
border: BorderStroke? = SurfaceDefaults.border(),
contentPadding: PaddingValues = ListItemDefaults.contentPadding,
interactionSource: MutableInteractionSource? = null,
content: @Composable () -> Unit,
) {
ListItemImpl(
modifier = modifier,
onClick = onClick,
supportingLabel = supportingLabel,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
shape = shape,
color = color,
contentColor = contentColor,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
}
@Composable
private fun ListItemImpl(
modifier: Modifier,
onClick: (() -> Unit)?,
supportingLabel: @Composable (() -> Unit)?,
leadingIcon: @Composable (() -> Unit)?,
trailingIcon: @Composable (() -> Unit)?,
shape: Shape,
color: Color,
contentColor: Color,
border: BorderStroke?,
contentPadding: PaddingValues,
interactionSource: MutableInteractionSource?,
content: @Composable () -> Unit,
) {
val iconSize = GlimmerTheme.iconSizes.large
val typography = GlimmerTheme.typography
val innerPadding = GlimmerTheme.componentSpacingValues.small
val internalInteractionSource = interactionSource ?: remember { MutableInteractionSource() }
val surfaceModifier =
Modifier.surface(
shape = shape,
color = color,
contentColor = contentColor,
// TODO(b/532516157): Reenable depthEffect after b/446294492 is fixed.
depthEffect = null,
border = border,
interactionSource = internalInteractionSource,
)
.then(
if (onClick != null) {
Modifier.clickable(
interactionSource = internalInteractionSource,
onClick = onClick,
)
} else {
Modifier.focusable(interactionSource = internalInteractionSource)
}
)
Row(
modifier =
modifier
.then(surfaceModifier)
.fillMaxWidth()
.defaultMinSize(minHeight = MinimumHeight)
.padding(contentPadding),
verticalAlignment = CenterVertically,
) {
if (leadingIcon != null) {
Box(modifier = Modifier.align(Alignment.Top), contentAlignment = Alignment.TopStart) {
CompositionLocalProvider(LocalIconSize provides iconSize, content = leadingIcon)
}
}
Column(Modifier.weight(1f).padding(horizontal = innerPadding)) {
if (supportingLabel == null) {
CompositionLocalProvider(
LocalTextStyle provides typography.bodySmall,
content = content,
)
} else {
CompositionLocalProvider(
LocalTextStyle provides typography.titleSmall,
content = content,
)
CompositionLocalProvider(
LocalTextStyle provides typography.bodySmall,
content = supportingLabel,
)
}
}
if (trailingIcon != null) {
Box(modifier = Modifier.align(Alignment.Top), contentAlignment = Alignment.TopEnd) {
CompositionLocalProvider(LocalIconSize provides iconSize, content = trailingIcon)
}
}
}
}
/** Default values used for [ListItem] */
public object ListItemDefaults {
/** Default content padding used for a [ListItem] */
public val contentPadding: PaddingValues
@Composable get() = PaddingValues(GlimmerTheme.componentSpacingValues.large)
}
/** Default minimum height for a [ListItem] */
private val MinimumHeight = 80.dp
```
<br />