Abh*_*bhi 20 android tooltip android-jetpack-compose
我正在尝试在我的应用程序 UI 中添加一个简单的工具提示,用于FAB、IconButton、Menu等。
如何将其添加到jetpack compose中?
我熟悉如何使用 XML 和以编程方式进行添加,如此处所述。
这些方法的局限性 - 尝试尽可能避免 XML,对于编程方法,出于明显的原因,compose 中没有 findViewById。
参考Jetpack 文档、Codelab和示例。
没有任何与工具提示相关的内容。
任何帮助表示赞赏。
注意
不要寻找任何自定义项,简单明了的工具提示就可以了。
最好没有第三方库。
更新
任何有相同要求的人,请提出这个问题。
Art*_*pov 18
更新
\n自版本1.1.0(于 2023 年 \xc2\xa0May\xc2\xa010 发布)以来,Jetpack Compose Material 3\xc2\xa0 现在包含官方工具提示。\xc2\xa0 有两种类型:plain\xc2\xa0tooltips ( PlainTooltipBox) 和rich\xc2\xa0tooltips ( RichTooltipBox)。
1.1.0-alpha05,2023 年 1 月\xc2\xa011简单的工具提示简要描述了 UI 元素。普通工具提示非常适合标记没有文本的 UI 元素,例如仅图标和字段元素。
\n\n要将普通工具提示应用于 xc2xa0 任何组件,请使用 包裹组件并将组件PlainTooltipBox()添加Modifier.tooltipAnchor()到 xe2x80x99s 修饰符:
import androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.PlainTooltipBox\nimport androidx.compose.material3.Text\n\nPlainTooltipBox(\n tooltip = { Text("Present now") }\n) {\n IconButton(\n onClick = { /* Icon button\'s click event */ },\n modifier = Modifier.tooltipTrigger()\n ) {\n Icon(\n imageVector = Icons.Filled.FilePresent,\n contentDescription = "Present now"\n )\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n丰富的工具提示非常适合较长的文本,例如\xc2\xa0definitions 或\xc2\xa0explanations。丰富的工具提示为\xc2\xa0a\xc2\xa0UI 元素提供了额外的上下文,并且可以包含\xc2\xa0 按钮或\xc2\xa0 超链接。
\n\n您可以通过\xc2\xa0向 提供参数来获得持久或\xc2\xa0非持久的丰富工具isPersistent提示RichTooltipState()。要\xc2\xa0关闭持久工具提示,您需要\xc2\xa0点击工具提示区域之外或\xc2\xa0调用工具提示状态上的\xc2\xa0关闭操作。
非持久性工具提示会在短暂的持续时间后自动消失。
\n要添加丰富的工具提示,您可以使用可RichTooltipBox()组合项并修改工具提示状态来控制工具提示的可见性。
val tooltipState = remember { RichTooltipState() }\nval scope = rememberCoroutineScope()\nRichTooltipBox(\n title = { Text("Add others") },\n action = {\n TextButton(\n onClick = { scope.launch { tooltipState.dismiss() } }\n ) { Text("Learn More") }\n },\n text = { Text("Share this collection with friends...") },\n tooltipState = tooltipState\n) {\n IconButton(\n onClick = { /* Icon button\'s click event */ },\n modifier = Modifier.tooltipTrigger()\n ) {\n Icon(\n imageVector = Icons.Filled.People,\n contentDescription = "Add others"\n )\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n旧答案,对于手动实施仍然有用。
\n截至 2021 年 10 月 21 日,Jetpack Compose 中没有可组合的官方工具提示。
\n但是可以使用 有效地构建一个漂亮的工具提示androidx.compose.ui.window.Popup。
\n我们可以以具体的DropdownMenu实现作为起点。
如何在长按时显示工具提示(使用示例):
\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimport androidx.compose.foundation.combinedClickable\nimport androidx.compose.foundation.interaction.MutableInteractionSource\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.material.Text\nimport androidx.compose.material.ripple.rememberRipple\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.semantics.Role\n\n@Composable\n@OptIn(ExperimentalFoundationApi::class)\nfun TooltipOnLongClickExample(onClick: () -> Unit = {}) {\n // Commonly a Tooltip can be placed in a Box with a sibling\n // that will be used as the \'anchor\' for positioning.\n Box {\n val showTooltip = remember { mutableStateOf(false) }\n\n // Buttons and Surfaces don\'t support onLongClick out of the box,\n // so use a simple Box with combinedClickable\n Box(\n modifier = Modifier\n .combinedClickable(\n interactionSource = remember { MutableInteractionSource() },\n indication = rememberRipple(),\n onClickLabel = "Button action description",\n role = Role.Button,\n onClick = onClick,\n onLongClick = { showTooltip.value = true },\n ),\n ) {\n Text("Click Me (will show tooltip on long click)")\n }\n\n Tooltip(showTooltip) {\n // Tooltip content goes here.\n Text("Tooltip Text!!")\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n 工具提示可组合源代码:
\n@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")\n\nimport androidx.compose.animation.core.MutableTransitionState\nimport androidx.compose.animation.core.animateFloat\nimport androidx.compose.animation.core.tween\nimport androidx.compose.animation.core.updateTransition\nimport androidx.compose.foundation.layout.*\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.alpha\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.takeOrElse\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.platform.LocalDensity\nimport androidx.compose.ui.unit.DpOffset\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.window.Popup\nimport androidx.compose.ui.window.PopupProperties\nimport androidx.core.graphics.ColorUtils\nimport kotlinx.coroutines.delay\n\n\n/**\n * Tooltip implementation for AndroidX Jetpack Compose.\n * Based on material [DropdownMenu] implementation\n *\n * A [Tooltip] behaves similarly to a [Popup], and will use the position of the parent layout\n * to position itself on screen. Commonly a [Tooltip] will be placed in a [Box] with a sibling\n * that will be used as the \'anchor\'. Note that a [Tooltip] by itself will not take up any\n * space in a layout, as the tooltip is displayed in a separate window, on top of other content.\n *\n * The [content] of a [Tooltip] will typically be [Text], as well as custom content.\n *\n * [Tooltip] changes its positioning depending on the available space, always trying to be\n * fully visible. It will try to expand horizontally, depending on layout direction, to the end of\n * its parent, then to the start of its parent, and then screen end-aligned. Vertically, it will\n * try to expand to the bottom of its parent, then from the top of its parent, and then screen\n * top-aligned. An [offset] can be provided to adjust the positioning of the menu for cases when\n * the layout bounds of its parent do not coincide with its visual bounds. Note the offset will\n * be applied in the direction in which the menu will decide to expand.\n *\n * @param expanded Whether the tooltip is currently visible to the user\n * @param offset [DpOffset] to be added to the position of the tooltip\n *\n * @see androidx.compose.material.DropdownMenu\n * @see androidx.compose.material.DropdownMenuPositionProvider\n * @see androidx.compose.ui.window.Popup\n *\n * @author Artyom Krivolapov\n */\n@Composable\nfun Tooltip(\n expanded: MutableState<Boolean>,\n modifier: Modifier = Modifier,\n timeoutMillis: Long = TooltipTimeout,\n backgroundColor: Color = Color.Black,\n offset: DpOffset = DpOffset(0.dp, 0.dp),\n properties: PopupProperties = PopupProperties(focusable = true),\n content: @Composable ColumnScope.() -> Unit,\n) {\n val expandedStates = remember { MutableTransitionState(false) }\n expandedStates.targetState = expanded.value\n\n if (expandedStates.currentState || expandedStates.targetState) {\n if (expandedStates.isIdle) {\n LaunchedEffect(timeoutMillis, expanded) {\n delay(timeoutMillis)\n expanded.value = false\n }\n }\n\n Popup(\n onDismissRequest = { expanded.value = false },\n popupPositionProvider = DropdownMenuPositionProvider(offset, LocalDensity.current),\n properties = properties,\n ) {\n Box(\n // Add space for elevation shadow\n modifier = Modifier.padding(TooltipElevation),\n ) {\n TooltipContent(expandedStates, backgroundColor, modifier, content)\n }\n }\n }\n}\n\n\n/** @see androidx.compose.material.DropdownMenuContent */\n@Composable\nprivate fun TooltipContent(\n expandedStates: MutableTransitionState<Boolean>,\n backgroundColor: Color,\n modifier: Modifier,\n content: @Composable ColumnScope.() -> Unit,\n) {\n // Tooltip open/close animation.\n val transition = updateTransition(expandedStates, "Tooltip")\n\n val alpha by transition.animateFloat(\n label = "alpha",\n transitionSpec = {\n if (false isTransitioningTo true) {\n // Dismissed to expanded\n tween(durationMillis = InTransitionDuration)\n } else {\n // Expanded to dismissed.\n tween(durationMillis = OutTransitionDuration)\n }\n }\n ) { if (it) 1f else 0f }\n\n Card(\n backgroundColor = backgroundColor.copy(alpha = 0.75f),\n contentColor = MaterialTheme.colors.contentColorFor(backgroundColor)\n .takeOrElse { backgroundColor.onColor() },\n modifier = Modifier.alpha(alpha),\n elevation = TooltipElevation,\n ) {\n val p = TooltipPadding\n Column(\n modifier = modifier\n .padding(start = p, top = p * 0.5f, end = p, bottom = p * 0.7f)\n .width(IntrinsicSize.Max),\n content = content,\n )\n }\n}\n\nprivate val TooltipElevation = 16.dp\nprivate val TooltipPadding = 16.dp\n\n// Tooltip open/close animation duration.\nprivate const val InTransitionDuration = 64\nprivate const val OutTransitionDuration = 240\n\n// Default timeout before tooltip close\nprivate const val TooltipTimeout = 2_000L - OutTransitionDuration\n\n\n// Color utils\n\n/**\n * Calculates an \'on\' color for this color.\n *\n * @return [Color.Black] or [Color.White], depending on [isLightColor].\n */\nfun Color.onColor(): Color {\n return if (isLightColor()) Color.Black else Color.White\n}\n\n/**\n * Calculates if this color is considered light.\n *\n * @return true or false, depending on the higher contrast between [Color.Black] and [Color.White].\n *\n */\nfun Color.isLightColor(): Boolean {\n val contrastForBlack = calculateContrastFor(foreground = Color.Black)\n val contrastForWhite = calculateContrastFor(foreground = Color.White)\n return contrastForBlack > contrastForWhite\n}\n\nfun Color.calculateContrastFor(foreground: Color): Double {\n return ColorUtils.calculateContrast(foreground.toArgb(), toArgb())\n}\nRun Code Online (Sandbox Code Playgroud)\n 使用 AndroidX Jetpack Compose 版本进行测试1.1.0-alpha06
请参阅带有完整示例的要点:
\n https://gist.github.com/amal/aad53791308e6edb055f3cf61f881451
通过 M3,您可以使用可PlainTooltipBox组合项:
就像是:
PlainTooltipBox(
tooltip = { Text("Add to favorites" ) },
contentColor = White,
) {
IconButton(
onClick = { /* Icon button's click event */ },
modifier = Modifier.tooltipAnchor()
) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = "Localized Description"
)
}
}
Run Code Online (Sandbox Code Playgroud)
长按时会调用工具提示anchor。
如果您想通过事件单击显示工具提示,您可以使用:
val tooltipState = remember { PlainTooltipState() }
val scope = rememberCoroutineScope()
PlainTooltipBox(
tooltip = { Text("Add to favorites" ) },
tooltipState = tooltipState
) {
IconButton(
onClick = { /* Icon button's click event */ },
modifier = Modifier.tooltipAnchor()
) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = "Localized Description"
)
}
}
Spacer(Modifier.requiredHeight(30.dp))
OutlinedButton(
onClick = { scope.launch { tooltipState.show() } }
) {
Text("Display tooltip")
}
Run Code Online (Sandbox Code Playgroud)
Jetpack Compose尚无官方tooltip支持。
你可能可以在上面构建一些东西androidx.compose.ui.window.Popup(...)
另外,我还会查看TextDelegate来测量文本,以便了解工具提示/弹出窗口的位置和方式。
| 归档时间: |
|
| 查看次数: |
14119 次 |
| 最近记录: |