Compose のテキスト

テキストは UI の主要な構成要素です。Jetpack Compose を使用すると、テキストの表示や入力を簡単に行うことができます。Compose では構成要素のコンポジションを利用できるため、特定のコンポーザブルの設計とロジックを意図したとおりに機能させるにあたり、プロパティやメソッドを上書きしたり、大きなクラスを拡張したりする必要はありません。

Compose には、テキストの表示とユーザー入力の処理に最低限必要な BasicTextBasicTextField がベースとして用意されています。その上位レベルでは、マテリアル デザイン ガイドラインに沿ったコンポーザブルである TextTextField を利用できます。Android ユーザーに適切な外観と操作感を提供できるほか、多くのコードを書かなくても簡単にカスタマイズできるオプションも利用できるため、これらのコンポーザブルを使用することをおすすめします。

テキストの表示

テキストを表示するための最も基本的な方法は、引数として String を指定して Text コンポーザブルを使用することです。

@Composable
fun SimpleText() {
  Text("Hello World")
}

黒色のプレーン テキストで「Hello World」という語句を表示

リソースを使用してテキストを表示する

Text の値をハードコードするのではなく、文字列リソースを使用することをおすすめします。これにより、Android ビューと同じ文字列を共有できるだけでなく、アプリの国際化もしやすくなります。

@Composable
fun StringResourceText() {
  Text(stringResource(R.string.hello_world))
}

テキストのスタイル設定

Text コンポーザブルには、コンテンツのスタイル設定を行うためのオプションのパラメータが複数用意されています。以下に、テキストに関する最も一般的なユースケースに対応するパラメータを示します。Text のすべてのパラメータを確認するには、Compose Text ソースコードをご覧ください。

これらのパラメータを設定すると、テキスト値全体にスタイルが適用されます。同じ行や段落内に複数のスタイルを適用する必要がある場合は、複数のインライン スタイルのセクションをご覧ください。

テキストの色を変更する

@Composable
fun BlueText() {
  Text("Hello World", color = Color.Blue)
}

「Hello World」という語句を青色のテキストで表示

文字サイズを変更する

@Composable
fun BigText() {
  Text("Hello World", fontSize = 30.sp)
}

「Hello World」という語句を大きな文字サイズで表示

テキストを斜体にする

@Composable
fun ItalicText() {
  Text("Hello World", fontStyle = FontStyle.Italic)
}

「Hello World」という語句を斜体で表示

テキストを太字にする

@Composable
fun BoldText() {
    Text("Hello World", fontWeight = FontWeight.Bold)
}

「Hello World」という語句を太字で表示

テキストの配置

textAlign パラメータを使用すると、Text コンポーザブルの面積内でのテキストの配置を設定できます。

デフォルトでは、Text はコンテンツの値に応じて自然なテキストの配置を選択します。

  • Text コンテナの左端: ラテン文字、キリル文字、ハングルなど、左から右に記述するアルファベットの場合
  • Text コンテナの右端: アラビア語やヘブライ語など、右から左に記述するアルファベットの場合
@Preview(showBackground = true)
@Composable
fun CenterText() {
    Text("Hello World", textAlign = TextAlign.Center,
                modifier = Modifier.width(150.dp))
}

「Hello World」という語句をコンテナ要素の中央に表示

Text コンポーザブルのテキストの配置を手動で設定する場合は、TextAlign.LeftTextAlign.Right の代わりに TextAlign.StartTextAlign.End を使用します。これにより、使用する言語のテキストの向きに応じて、テキストが Text コンポーザブルの適切な側に解決されます。たとえば、TextAlign.End では、フランス語テキストは右側、アラビア語テキストは左側に配置されます。一方、TextAlign.Right では、使用されているアルファベットの種類にかかわらず、テキストが右側に配置されます。

フォントの操作

Text には、コンポーザブルで使用されるフォントを設定するための fontFamily パラメータを指定できます。デフォルトでは、Serif、Sans Serif、等幅、Cursive のフォント ファミリーが含まれています。

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

「Hello World」という語句を 2 つのフォント(セリフありとセリフなし)で表示

fontFamily 属性を使用して、res/fonts フォルダで定義されているカスタムのフォントと書体を操作できます。

開発環境の res > font フォルダの図

次の例は、これらのフォント ファイルに基づいて fontFamily を定義する方法を示しています。

val firaSansFamily = FontFamily(
        Font(R.font.firasans_light, FontWeight.Light),
        Font(R.font.firasans_regular, FontWeight.Normal),
        Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
        Font(R.font.firasans_medium, FontWeight.Medium),
        Font(R.font.firasans_bold, FontWeight.Bold)
)

最後に、この fontFamilyText コンポーザブルに渡すことができます。fontFamily には、異なる太さを含めることが可能です。その場合は、次のように手動で fontWeight を設定して、テキストに適した太さを選択します。

Column {
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal,
                    fontStyle = FontStyle.Italic)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

「Hello World」という語句をさまざまな太さとスタイルで表示

アプリ全体のタイポグラフィを設定する方法については、テーマのドキュメントをご覧ください。

1 つのテキストに複数のスタイルを設定する

同じ Text コンポーザブルに複数のスタイルを設定するには、AnnotatedString を使用する必要があります。これは、任意のアノテーションのスタイルでアノテーションを付けることができる文字列です。

AnnotatedString は、以下を含むデータクラスです。

  • Text
  • SpanStyleRangeList(テキスト値内の位置範囲を使用したインライン スタイル設定と同等です)
  • ParagraphStyleRangeList(テキストの配置、テキスト方向、行の高さ、テキストのインデント スタイルを指定します)

TextStyleText コンポーザブルで使用され、SpanStyleParagraphStyleAnnotatedString で使用されます。

SpanStyleParagraphStyle の違いは、ParagraphStyle は段落全体に適用できるのに対し、SpanStyle は文字単位で適用できる点にあります。テキストの一部を ParagraphStyle でマークすると、その部分は先頭と末尾にラインフィードがあるものとして残りのテキストから分離されます。

AnnotatedString は、タイプセーフなビルダーを使用して簡単に作成できます。

@Composable
fun MultipleStylesInText() {
    Text(buildAnnotatedString {
        withStyle(style = SpanStyle(color = Color.Blue)) {
            append("H")
        }
        append("ello ")

        withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
            append("W")
        }
        append("orld")
    })
}

「Hello World」という語句を、インラインで複数のスタイル変更(H は青色、W は赤色と太字)を行って表示

段落スタイルも同じ方法で設定できます。

@Composable
fun ParagraphStyle() {
    Text(buildAnnotatedString {
        withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
            withStyle(style = SpanStyle(color = Color.Blue)) {
                append("Hello\n")
            }
            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold,
                                        color = Color.Red)) {
                append("World\n")
            }
            append("Compose")
        }
    })
}

3 つの段落を 3 種類のスタイル(青色、赤色と太字、黒色)で表示

最大行数

Text コンポーザブルに表示する行数を制限するには、maxLines パラメータを設定します。

@Composable
fun LongText() {
    Text("hello ".repeat(50), maxLines = 2)
}

2 行表示された後に切り捨てられた長いテキスト

テキスト オーバーフロー

長いテキストを制限する場合は、テキスト オーバーフローを指定することをおすすめします。テキスト オーバーフローは、表示されているテキストが切り捨てられた場合にのみ表示されます。これを行うには、textOverflow パラメータを設定します。

@Composable
fun OverflowedText() {
    Text("Hello Compose ".repeat(50), maxLines = 2, overflow = TextOverflow.Ellipsis)
}

2 行表示された後に切り捨てられた長いテキスト。末尾に省略記号が表示されます

テーマ設定

テキストのスタイル設定にアプリのテーマを使用する場合は、テーマのドキュメントをご覧ください。

ユーザー操作

Jetpack Compose により、Text でのきめ細かい操作が可能となり、テキストをコンポーザブル レイアウト全体でより柔軟に選択できるようになりました。テキストでのユーザー操作では、他のコンポーザブル レイアウトとは異なり、Text コンポーザブルの一部に修飾子を追加することができません。このセクションでは、ユーザー操作を可能にするさまざまな API について説明します。

テキストの選択

コンポーザブルはデフォルトでは選択不可であるため、ユーザーがアプリからテキストを選択してコピーすることはできません。テキストの選択を有効にするには、テキスト要素を SelectionContainer コンポーザブルでラップする必要があります。

@Composable
fun SelectableText() {
    SelectionContainer {
        Text("This text is selectable")
    }
}

ユーザーが選択した短い文。

選択可能な領域の特定の部分で選択を無効にすることもできます。それには、選択不可にする部分を DisableSelection コンポーザブルでラップする必要があります。

@Composable
fun PartiallySelectableText() {
    SelectionContainer {
        Column {
            Text("This text is selectable")
            Text("This one too")
            Text("This one as well")
            DisableSelection {
                Text("But not this one")
                Text("Neither this one")
            }
            Text("But again, you can select this one")
            Text("And this one too")
        }
    }
}

長い文。ユーザーは文全体を選択しようとしましたが、DisableSelection が適用された 2 つの行は選択されませんでした。

テキストのクリック位置を取得する

Text のクリックをリッスンするには、clickable 修飾子を追加します。ただし、Text コンポーザブル内でクリック位置を取得して、その位置によって異なるアクションを提供する場合は、代わりに ClickableText を使用する必要があります。

@Composable
fun SimpleClickableText() {
    ClickableText(
        text = AnnotatedString("Click Me"),
        onClick = { offset ->
            Log.d("ClickableText", "$offset -th character is clicked.")
        }
    )
}

アノテーション付きのクリック

ユーザーが Text コンポーザブルをクリックしたときに、Text 値の一部に情報を追加することもできます(特定の単語にアタッチされている URL をブラウザで開く、など)。そのためには、タグ(String)、アイテム(String)、テキスト範囲をパラメータとして取るアノテーションを追加する必要があります。AnnotatedString から、これらのアノテーションをタグまたはテキスト範囲でフィルタできます。次に例を示します。

@Composable
fun AnnotatedClickableText() {
    val annotatedText = buildAnnotatedString {
        append("Click ")

        // We attach this *URL* annotation to the following content
        // until `pop()` is called
        pushStringAnnotation(tag = "URL",
                             annotation = "https://developer.android.com")
        withStyle(style = SpanStyle(color = Color.Blue,
                                    fontWeight = FontWeight.Bold)) {
            append("here")
        }

        pop()
    }

    ClickableText(
        text = annotatedText,
        onClick = { offset ->
            // We check if there is an *URL* annotation attached to the text
            // at the clicked position
            annotatedText.getStringAnnotations(tag = "URL", start = offset,
                                                    end = offset)
                .firstOrNull()?.let { annotation ->
                    // If yes, we log its value
                    Log.d("Clicked URL", annotation.item)
                }
        }
    )
}

テキストの入力と変更

TextField を使用すると、ユーザーがテキストの入力や変更を行えるようになります。TextField の実装には次の 2 つのレベルがあります。

  1. TextField はマテリアル デザインの実装であり、次のようなマテリアル デザイン ガイドラインに沿っているため、この実装を選択することをおすすめします。
    • デフォルトのスタイル設定は塗りつぶしです。
    • OutlinedTextField は、枠線のスタイル設定バージョンです。
  2. BasicTextField を使用すると、ユーザーはハードウェア キーボードまたはソフトウェア キーボードを使用してテキストを編集できます。ただし、ヒントやプレースホルダのような装飾は用意されていません。
@Composable
fun SimpleFilledTextFieldSample() {
    var text by remember { mutableStateOf("Hello") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

「Hello」という単語が入力された編集可能なテキスト フィールド。フィールドに編集不可のラベル「Label」が含まれています。

@Composable
fun SimpleOutlinedTextFieldSample() {
    var text by remember { mutableStateOf("") }

    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

紫色の枠線とラベルが付いた編集可能なテキスト フィールド。

TextField のスタイル設定

TextFieldBasicTextField は、カスタマイズ用のパラメータを多数共有しています。TextField の完全なリストについては、TextField ソースコードをご覧ください。有用なパラメータの一部を以下に示します。

  • singleLine
  • maxLines
  • textStyle
@Composable
fun StyledTextField() {
    var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }

    TextField(
        value = value,
        onValueChange = { value = it },
        label = { Text("Enter text") },
        maxLines = 2,
        textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

ラベルと 2 つの編集可能な行がある、複数行の TextField

デザインにマテリアルの TextField または OutlineTextField が必要な場合は、BasicTextField ではなく TextField をおすすめします。ただし、マテリアル仕様の装飾を必要としないデザインをビルドする場合には、BasicTextField を使用する必要があります。

キーボード オプション

TextField を使用すると、キーボード レイアウトなどのキーボード構成オプションを設定できます。また、キーボードでサポートされている場合は、自動修正を有効にすることも可能です。ソフトウェア キーボードが次に示すオプションに対応していない場合、一部のオプションは保証されない可能性があります。サポートされているキーボード オプションのリストを次に示します。

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

形式

TextField を使用すると、入力値に形式を設定できます。たとえば、パスワードの文字を * で置き換えたり、クレジット カード番号の 4 桁の数字ごとにハイフンを挿入したりできます。

@Composable
fun PasswordTextField() {
    var password by rememberSaveable { mutableStateOf("") }

    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("Enter password") },
        visualTransformation = PasswordVisualTransformation(),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
    )
}

文字がマスクされたパスワード入力欄

その他の例については、VisualTransformSamples ソースコードをご覧ください。