5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jetpack Composeで特定の部分だけ文字色を変える方法

Last updated at Posted at 2025-02-17

【備考】
HTMLCompatというクラスを使用してHTML文字列の部分だけ文字色を変える方法を学んだため記録として残します。
漏れや不備等があるかもしれないため、その点ご理解いただけますと幸いです:bow:

やりたいこと

▼こんな感じに一部だけ文字色を変えたい

ざっくり手順

① HTML文字列の準備する
② 再利用できるようにHTML形式の文字列を表示するためのComposable関数を作成する
③ 作成したComposable関数を必要な場所で呼び出して表示する

① HTML文字列の準備

HTML形式(例えば タグで部分的に文字色を変えるなど)を使った文字列を用意します。

▼例

"ご覧いただきありがとうございます。HTML形式のテキストを<font color='#ed293e'>一部赤色の文字で表示します。</font>"

② Composable関数を作成

HTML形式の文字列を表示するためにComposable関数を作成します。
補足として、再利用しやすい命名にすると良さそうです。
以下細かな手順です。

1. HTMLCompatを使ってHTMLを変換する

HtmlCompat.fromHtmlを使用して、HTML文字列を変換し、spannedという変数に格納します。

val spanned = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)

【補足】

HtmlCompat.fromHtmlとは?
HtmlCompatはAndroidxに含まれる標準ライブラリ。 fromHtmlメソッドはHTML文字列をSpannedに変換してくれます。 Spannedは文字列にスタイルやフォーマットを適応するためのインターフェースなので、Spannedを使って特定の部分に色をつけていきます。

参考:公式ドキュメント

2. スタイルの適用

以下、要点となります。

  1. buildAnnotatedStringを使用して、「1. HTMLCompatを使ってHTMLを変換する」のSpannedにスタイルを適応します。【補足1】
  2. spanned.getSpansメソッドを使用して、指定された範囲内のスタイルなどを取得します。【補足2】
  3. whenを使用してForegroundColorSpanの場合、テキストの色を設定するよう条件分岐をします。【補足3】
  4. spanned.getSpanStart(it)spanned.getSpanEnd(it)を使用して、スタイルを適用する範囲を指定します。
  5. 最後にappend(spanned)で変換されたスタイルを追加します。
【補足1】
buildAnnotatedStringとは?
テキストに複数の装飾付きの文字列を作成する関数です。
【補足2】
CharacterStyleについて

CharacterStyleは文字のスタイルを適応するための抽象クラスで、具体的には以下のようなスタイルを適応するサブクラスがあります。

  • ForegroundColorSpan: 文字の前景色(テキストの色)を変更します。
  • BackgroundColorSpan: 文字の背景色を変更します。
  • StyleSpan: 文字のスタイル(太字、斜体など)を変更します。
  • UnderlineSpan: 文字に下線を引きます。
  • StrikethroughSpan: 文字に取り消し線を引きます。

ここでは、Spannedの文字全体からスタイル適応に該当する文字部分を取得しているイメージです。

今回は文字色を変えたいのでForegroundColorSpanが返ってくることを期待します!

参考:公式ドキュメント

【補足3】
whenを使っている理由は?
CharacterStyleのインスタンスがForegroundColorSpanである場合に、色情報を取得してSpanStyleに適用するため。その他の型の場合は何もしません。
サンプルコード(閉じれます)
val annotatedText = buildAnnotatedString {
        spanned.getSpans(0, spanned.length, CharacterStyle::class.java).forEach {
            // フォントのスパンにスタイルを適用
            when (it) {
                is ForegroundColorSpan -> {
                    // itはForegroundColorSpanのインスタンス
                    val color = it.foregroundColor
                    addStyle(
                        SpanStyle(
                            color = Color(color),
                        ),
                        spanned.getSpanStart(it),
                        spanned.getSpanEnd(it),
                    )
                }
                else -> {
                    // 何もしない
                }
            }
        }
        append(spanned)
    }

3. テキストの表示

スタイルが適用されたテキストを表示します。

Text(
    modifier = modifier,
    text = annotatedText,
    style = textStyle.merge(
         TextStyle(fontSize = fontSize),
    ),
)

ここまでの全コード

ここまでのコード(閉じれます)
@Composable
fun HtmlText(
    html: String,
    fontSize: TextUnit,
    modifier: Modifier = Modifier,
    textStyle: TextStyle = LocalTextStyle.current,
) {
    val spanned = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
    val annotatedText = buildAnnotatedString {
        spanned.getSpans(0, spanned.length, CharacterStyle::class.java).forEach {
            when (it) {
                is ForegroundColorSpan -> {
                    val color = it.foregroundColor
                    addStyle(
                        SpanStyle(
                            color = Color(color),
                        ),
                        spanned.getSpanStart(it),
                        spanned.getSpanEnd(it),
                    )
                }
                else -> {
                    // 何もしない
                }
            }
        }
        append(spanned)
    }
    Text(
        modifier = modifier,
        text = annotatedText,
        style = textStyle.merge(
            TextStyle(fontSize = fontSize),
        ),
    )
}

③ 作成したComposable関数を必要な場所で呼び出して表示する

@Composable
fun SampleScreen() {
    val sampleHtml = "ご覧いただきありがとうございます。HTML形式のテキストを<font color='#ed293e'>一部赤色の文字で表示します。</font>"

    HtmlText(
        html = sampleHtml,
    )
}

▼Previewですがこんな感じになります

以上となります。
最後までご覧いただきありがとうございました:thumbsup_tone1:

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?