當我寫了我的上一篇文章關於Jetpack Compose時,我曾在那裡提到Jetpack Compose缺少一些(在我看來)基本的元件,其中之一就是 Tooltip。
當時,沒有內建的可組合來顯示Tooltip,而在網上 circulating 有一些替代方案。這些方案的問題是,一旦Jetpack Compose推出新的版本,這些方案可能會損壞。所以這不是理想的選擇,社區只能他希望未來某個时候可以添加對 Tooltip 的支持。
我很高兴地告訴大家,自Compose Material 3 1.1.0版本以來,我們现在已经有了內建的Tooltip支持。👏
雖然這本身已經很好了,但自那版本發布以來已經过了一年多。並且在隨後的版本中,與Tooltips相關的API也發生了很大的變化。
如果你查看更改記錄,你會看到公用的和內部API的變化。所以請注意,當你閱讀這篇文章時,由於與Tooltips相關的都被標記為ExperimentalMaterial3Api::class,所以事情可能繼續在變化。
❗️ 本文使用的 material 3 版本是 1.2.1,該版本於 2024 年 3 月 6 日發布。
Tooltip 類型
現在我們支持兩種不同類型的 Tooltip:
-
普通 Tooltip
-
豐富媒體提示
簡易提示
您可以使用第一種方式提供有關圖示按鈕的信息,否則可能不清楚。例如,您可以使用簡易提示向用戶解釋圖示按鈕代表什麼。
要向應用程式添加提示,您可以使用TooltipBox組合。此組合接受幾個參數:
fun TooltipBox(
positionProvider: PopupPositionProvider,
tooltip: @Composable TooltipScope.() -> Unit,
state: TooltipState,
modifier: Modifier = Modifier,
focusable: Boolean = true,
enableUserInput: Boolean = true,
content: @Composable () -> Unit,
)
如果您之前使用過組合,其中一些參數可能會很熟悉。我將突出一下這裡具有特定用例的參數:
-
positionProvider – 屬於 PopupPositionProvider 類型,用於計算提示的位置。
-
tooltip – 這是您設計提示外觀的地方。
-
state – 這保存與特定提示實例相關聯的狀態。它公開方法,如顯示/隱藏提示,並在實例化其中一個時,您可以聲明提示是否應該是持久的(即是否應該一直顯示在屏幕上,直到用戶在提示外執行點擊操作)。
-
內容 – 這是 tooltip 將顯示在上方/下方的 UI。
以下是一個填滿所有相關參數的 BasicTooltipBox 實例化的例子:
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
fun BasicTooltip() {
val tooltipPosition = TooltipDefaults.rememberPlainTooltipPositionProvider()
val tooltipState = rememberBasicTooltipState(isPersistent = false)
BasicTooltipBox(positionProvider = tooltipPosition,
tooltip = { Text("Hello World") } ,
state = tooltipState) {
IconButton(onClick = { }) {
Icon(imageVector = Icons.Filled.Favorite,
contentDescription = "Your icon's description")
}
}
}
Jetpack Compose 有一個內置類叫做 TooltipDefaults。您可以使用這個類來幫助您實例化组成 TooltipBox 的參數。例如,您可以使用 TooltipDefaults.rememberPlainTooltipPositionProvider 正確地將 tooltip 定位在锚點元素的相關位置。
Rich Tooltip
一個 rich media tooltip 比一個 plain tooltip 佔用更多的空間,並且可以用於提供關於圖標按鈕功能性的更多上下文。當 tooltip 顯示時,您可以向其添加按鈕和鏈接以提供進一步的解释或定義。
它的實例化方式與 plain tooltip 類似,都在 TooltipBox 內,但您使用 RichTooltip 可 composable。
TooltipBox(positionProvider = tooltipPosition,
tooltip = {
RichTooltip(
title = { Text("RichTooltip") },
caretSize = caretSize,
action = {
TextButton(onClick = {
scope.launch {
tooltipState.dismiss()
tooltipState.onDispose()
}
}) {
Text("Dismiss")
}
}
) {
Text("This is where a description would go.")
}
},
state = tooltipState) {
IconButton(onClick = {
/* 图标按钮的点击事件 */
}) {
Icon(imageVector = tooltipIcon,
contentDescription = "Your icon's description",
tint = iconColor)
}
}
关于 Rich tooltip 有一些要注意的事情:
-
Rich tooltip 支持 caret。
-
您可以向 tooltip 加入一個動作(也就是一個按鈕),提供給使用者選擇查找更多資訊的選項。
-
您可以加入邏輯來關閉 tooltip。
邊界案例
當您選擇將您的tooltip 狀態標記為持久時,這意味著一旦使用者與顯示您的 tooltip 的 UI 進行互動,它將保持可见直到使用者在屏幕上按其他地方。
如果您查看上方 rich tooltip 的範例,您可能會發現我們已經在 tooltip 被點擊後加入了一個按鈕來關閉 tooltip。
當使用者按下那個按鈕時会发生一個問題。由於關閉動作是在 tooltip 上執行的,如果使用者想要在這個 tooltip 所呼叫的 UI 项目中執行另一次長按,則 tooltip 不会再顯示。這意味著 tooltip 的狀態在關閉後是持久的。那麼,我們应该如何解決這個問題?
為了“重置”tooltip 的狀態,我們必須呼叫透過 tooltip 狀態暴露的onDispose方法。一旦我們这样做,tooltip 狀態就会被重置,當使用者在 UI 项目中執行長按時,tooltip 將再次顯示。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RichTooltip() {
val tooltipPosition = TooltipDefaults.rememberRichTooltipPositionProvider()
val tooltipState = rememberTooltipState(isPersistent = true)
val scope = rememberCoroutineScope()
TooltipBox(positionProvider = tooltipPosition,
tooltip = {
RichTooltip(
title = { Text("RichTooltip") },
caretSize = TooltipDefaults.caretSize,
action = {
TextButton(onClick = {
scope.launch {
tooltipState.dismiss()
tooltipState.onDispose() /// <---- 這裡
}
}) {
Text("Dismiss")
}
}
) {
}
},
state = tooltipState) {
IconButton(onClick = { }) {
Icon(imageVector = Icons.Filled.Call, contentDescription = "Your icon's description")
}
}
}
另一個情境是,當工具提示被外部點擊而非透過用戶動作呼叫自身進行關閉時,工具提示狀態不會重置。這種情況下,工具提示在后台呼叫關閉方法,並將工具提示狀態設定為已關閉。如果長按UI元件以再次查看工具提示,則不會發生任何事情。
我們呼叫工具提示的 onDispose 方法的邏輯並未觸發,那麼我們如何重置工具提示的狀態呢?
目前我還沒能解決這個問題。這可能與工具提示的MutatorMutex有關。也许在未來的版本中,將有 API 處理這件事。我注意到,如果屏幕上存在其他工具提示,並且它們被點擊,這會重置先前點擊的工具提示。
如果您想查看這裡的代碼,您可以前往這個 GitHub 倉庫
如果您想在應用程序中查看工具提示,您可以這裡查看。
參考資料
Source:
https://www.freecodecamp.org/news/how-to-use-tooltips-in-jetpack-compose/