2023年8月2日 星期三

[Android] Jetpack Compose Text With Underline

 參考這篇文章後的補充。

取得TextLayoutResult的方法有兩種。

第一種:

    val textLayoutResultState = remember { mutableStateOf<textlayoutresult>(null) }
    Text(
        text = text,
        style = style,
        color = color,
        textAlign = textAlign,
        onTextLayout = {
            textLayoutResultState.value = it
        }
    )

第二種(style就包含fontSize和color):

    val textMeasurer = rememberTextMeasurer()
    val textResult = textMeasurer.measure(
           text = text,
           style = style
    )

取得TextLayoutResult後就可以讀取每個字空間大小

    text.indices.forEach { index ->
        val rect = textLayoutResultState.value!!.getBoundingBox(index)
        rectList.add(rect)
    }

如果要找特定字串的話可使用這方法

    val findText = "find some text"
    val startIndex = text.indexOf(findText)
    val endIndex = startIndex.plus(findText.length) - 1
    (startIndex..endIndex).forEach { index ->
        val rect = textLayoutResultState.value!!.getBoundingBox(index)
        rectList.add(rect)
    }

其中wave path的方法補充(對Path的擴展):

    const val TWO_PI = 2 * Math.PI.toFloat()
    private fun Path.buildWaveLinePath(bound: Rect, waveLength: Float, animProgress: Float): Path {
        asAndroidPath().rewind()
        var pointX = bound.left
        while (pointX < bound.right) {
            val offsetY =
                bound.bottom + sin(((pointX - bound.left) / waveLength)
                	* TWO_PI + (TWO_PI * animProgress)) * 10
            if (pointX == bound.left) {
                moveTo(bound.left, offsetY)
            }
            lineTo(pointX, offsetY)
            pointX += 1F
        }
        return this
}

使用wave path的方法:

    val infiniteTransition = rememberInfiniteTransition(label = "")
    val animProgress = infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(500, easing = LinearEasing)
        ), 
        label = ""
    )
    val start = rectList.first()!!.topLeft
    val end = rectList.last()!!.bottomRight
    val rect = Rect(start, end)
    val path = Path().buildWaveLinePath(rect, 50f, animProgress.value)
    val pathStyle = Stroke(
        width = 5f,
        pathEffect = PathEffect.cornerPathEffect(radius = 9.dp.toPx())
    )
    
    drawPath(
        color = Color.Yellow,
        path = path,
        style = pathStyle
    )    

沒有留言:

張貼留言