📝

Jetpack ComposeのTextがEllipsizeされたかを判断する

2021/12/12に公開
Android Advent Calendar 2021 12日目

Jetpack Composeは宣言的UIなので、Textのインスタンスを参照して状態を取得することができないのでどうするのか気になって調べた内容になります。

TextLayoutResult

Textコンポーザブルは、テキストがレイアウトされたときにTextLayoutResultをコールバックで受け取ることができるonTextLayoutという引数があります。これを使っていきます。

TextLayoutResultはコンポーザブルをレイアウトした結果を保持しているため、Textを描画したあとのレイアウトの状態を元に何かをするときはだいたいこれを活用することになりそうです。

Ellipsizeされたかを判断する

TextLayoutResultisLineEllipsizedメソッドがあるので、これを使うと良さそうです。

Text(
    text = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
    maxLines = 2,
    overflow = TextOverflow.Ellipsis,
    onTextLayout = { result ->
        val isEllipsized = result.isLineEllipsized(result.lineCount - 1)
        Log.d("Text", "isEllipsized = $isEllipsized")
    }
)

EllipsizeされているときにクリックでExpandする

簡易的ですが、クリックでExpandするComposableもこんなふうに作れそうです。

@Composable
fun ExpandableText(
    text: String,
    modifier: Modifier = Modifier,
    maxLines: Int = Int.MAX_VALUE,
    overflow: TextOverflow = TextOverflow.Ellipsis,
) {
    var isEllipsized by remember { mutableStateOf(false) }
    var currentMaxLines by remember { mutableStateOf(maxLines) }

    LaunchedEffect(isEllipsized) {
        if (!isEllipsized) currentMaxLines = Int.MAX_VALUE
    }

    Text(
        text = text,
        modifier = modifier
            .clickable(enabled = isEllipsized) { isEllipsized = !isEllipsized }
            .animateContentSize(),
        maxLines = currentMaxLines,
        overflow = overflow,
        onTextLayout = { result ->
            isEllipsized = result.isLineEllipsized(result.lineCount - 1)
        }
    )
}


こんなかんじ

Discussion