Jetpack Compose でのツールチップの使用:ステップバイステップ ガイド
Jetpack Compose に関する前回の記事を書いたとき、Jetpack Compose には (私の意見では) いくつかの基本コンポーネントが欠けており、その 1 つがツールチップであると述べました。
当時、ツールチップを表示するための組み込みコンポーザブルはなく、オンラインでいくつかの代替ソリューションが出回っていました。これらのソリューションの問題は、Jetpack Compose が新しいバージョンをリリースすると、それらのソリューションが壊れる可能性があることでした。したがって、これは理想的ではなく、コミュニティは将来的にツールヒントのサポートが追加されることを期待することになりました。
嬉しいことに、Compose Materials 3 のバージョン 1.1.0 以降、ツールチップのサポートが組み込まれています。 👏
これ自体は素晴らしいことですが、そのバージョンがリリースされてから 1 年以上が経過しました。そして、後続のバージョンでは、ツールチップに関連する API も大幅に変更されました。
変更ログを確認すると、パブリック API と内部 API がどのように変更されたかがわかります。この記事を読むときは、ツールチップに関連するすべてのものがまだ注釈 Experimentalmaterial3Api::class でマークされているため、状況は変わり続けている可能性があることに留意してください。 .
❗️ この記事で使用した資料 3 のバージョンは 1.2.1 で、2024 年 3 月 6 日にリリースされました
2 つの異なるタイプのツールチップがサポートされるようになりました。
<オル>プレーンなツールチップ
リッチメディア ツールチップ
プレーンなツールチップ
最初の種類を使用すると、他の方法ではわかりにくいアイコン ボタンに関する情報を提供できます。たとえば、プレーンなツールチップを使用して、アイコン ボタンが何を表すかをユーザーに示すことができます。

アプリケーションにツールチップを追加するには、ツールチップボックスを使用します。 構成可能。このコンポーザブルはいくつかの引数を取ります:
fun TooltipBox(
positionProvider: PopupPositionProvider,
tooltip: @Composable TooltipScope.() -> Unit,
state: TooltipState,
modifier: Modifier = Modifier,
focusable: Boolean = true,
enableUserInput: Boolean = true,
content: @Composable () -> Unit,
)
以前にコンポーザブルを使用したことがある場合は、これらのいくつかはよく知られているはずです。ここでは、特定の使用例を持つものを強調表示します。
-
PositionProvider - PopupPositionProvider の タイプであり、ツールチップの位置を計算するために使用されます。
-
ツールチップ - ここで、ツールチップがどのように見えるかについて UI をデザインできます。
-
state - 特定の Tooltip インスタンスに関連付けられた状態を保持します。これは、ツールチップの表示/非表示などのメソッドを公開しており、ツールチップのインスタンスをインスタンス化するときに、ツールチップを永続化するかどうか (ユーザーがツールチップの外側でクリック アクションを実行するまで画面上に表示し続ける必要があるかどうかを意味します) を宣言できます。
-
content - これは、ツールチップの上/下に表示される 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 を使用できます。 アンカー要素に対してツールチップを正しく配置します。
豊富なツールチップ
リッチ メディア ツールチップはプレーン ツールチップよりも多くのスペースを必要とし、アイコン ボタンの機能に関するより多くのコンテキストを提供するために使用できます。ツールチップが表示されたら、そこにボタンやリンクを追加して、さらに詳しい説明や定義を提供できます。
これは、TooltipBox 内でプレーン ツールチップと同様の方法でインスタンス化されますが、RichTooltip コンポーザブルを使用します。
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 button's click event */
}) {
Icon(imageVector = tooltipIcon,
contentDescription = "Your icon's description",
tint = iconColor)
}
}
リッチ ツールチップについて注意すべき点がいくつかあります。
<オル>リッチ ツールチップはキャレットをサポートしています。
ツールヒントにアクション (ボタン) を追加して、ユーザーに詳細情報を確認するオプションを提供できます。
ツールチップを閉じるロジックを追加できます。


エッジケース
ツールチップの状態を永続的としてマークすることを選択した場合 これは、ユーザーがツールチップを表示する UI を操作すると、ユーザーが画面上の他の場所を押すまで表示されたままになることを意味します。
上記のリッチ ツールチップの例をご覧になった方は、クリックするとツールチップを閉じるボタンが追加されていることに気づいたかもしれません。
ユーザーがそのボタンを押すと問題が発生します。閉じるアクションはツールチップで実行されるため、ユーザーがこのツールチップを呼び出す UI アイテムをもう一度長押ししても、ツールチップは再度表示されません。これは、ツールチップが閉じられてもその状態が維持されることを意味します。では、これをどうやって解決すればよいでしょうか?

ツールチップの状態を「リセット」するには、onDispose を呼び出す必要があります。 ツールチップの状態を通じて公開されるメソッド。これを行うと、ツールチップの状態がリセットされ、ユーザーが UI アイテムを長押しするとツールチップが再び表示されます。
@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() /// <---- HERE
}
}) {
Text("Dismiss")
}
}
) {
}
},
state = tooltipState) {
IconButton(onClick = { }) {
Icon(imageVector = Icons.Filled.Call, contentDescription = "Your icon's description")
}
}
}

ツールチップの状態がリセットされないもう 1 つのシナリオは、ユーザーのアクションごとに dismiss メソッドを呼び出す代わりに、ユーザーがツールチップの外側をクリックしてツールチップが閉じられた場合です。これにより、舞台裏で dismiss メソッドが呼び出され、ツールチップの状態が dismiss に設定されます。 UI 要素を長押ししてツールチップを再度表示しても、何も表示されません。

ツールチップの onDispose メソッドを呼び出すロジックはトリガーされません。では、ツールチップの状態をリセットするにはどうすればよいでしょうか?
現時点では、これを理解できませんでした。ツールチップの MutatorMutex に関連している可能性があります。おそらく今後のリリースでは、このための API が提供されるでしょう。他のツールチップが画面上に存在し、それを押すと、以前にクリックしたツールチップがリセットされることに気付きました。

ここで紹介されているコードを確認したい場合は、この GitHub リポジトリにアクセスしてください。
アプリケーションでツールチップを確認したい場合は、ここで確認できます。
参考文献
-
マテリアル 3 ツールチップの概要
-
ツールチップのデフォルト
-
ツールチップのソース コード
無料でコーディングを学びましょう。 freeCodeCamp のオープンソース カリキュラムは、40,000 人以上の人々が開発者としての職に就くのに役立ちました。始めましょう
-
最高のプライバシー重視のAndroidROMは何ですか?
スマートフォン愛好家は、プライバシーとセキュリティを何よりも優先するモバイルエコシステムを長い間切望してきました。これは、AndroidとiOSの両方がプライバシーを改善する大幅な更新を受け取ったものの、大量のトラッカーとサードパーティソフトウェアが同梱されているためです。 これらの慣行の影響について懸念がある場合は、朗報が間近に迫っています。 LineageOS、CalyxOS、GrapheneOSなどのカスタムROMは、スマートフォンのエクスペリエンスを完全にプライベートで安全なものにする方法を提供します。しかし、どちらがあなたに適していますか、そして一方のソリューションはもう一方とどの
-
Androidで通知を保存し、リマインダーを設定する方法
私のAndroidスマートフォンには非常に多くのアプリがあるため、当然のことながら多くの通知があります。それらの多くは、読むことなく却下することができます。アプリからの通知をブロックする組み込みツールがあるのはうれしいですが、一部の通知は非常に重要です。 問題は、通知が私の時間を尊重しないことです。 彼らは、私が望んでいるときではなく、彼らが望むときに現れます。 これを想像してください。あなたは忙しい一日の真っ只中にいます。丁!明日の会議についての友達からのメッセージについての通知を受け取ります。あなたは彼らに戻りたいのですが、あなたは今「ゾーンにいる」のです。ただし、今すぐに行わないと、