2023年8月1日 星期二

[Android] Create Outlined Text Using Jetpack Compose

在這篇文章中,介紹了兩種方式製作OutlinedText。

第一種:使用drawStyle(限制andriodx.core:core-ktx版本需要1.4.0-alpha01以上才有)

Text(
    text = "Sample",
    style = TextStyle.Default.copy(
        fontSize = 64.sp,
        drawStyle = Stroke(
            miter = 10f,
            width = 5f,
            join = StrokeJoin.Round
        )
    )
)

缺點:沒有繪製文字,只有文字外框


第二種:使用Canvas

// Creating a outline text
@Composable
fun OutLineText() {

    // Create a Paint that has black stroke
    val textPaintStroke = Paint().asFrameworkPaint().apply {
        isAntiAlias = true
        style = android.graphics.Paint.Style.STROKE
        textSize = 100f
        color = android.graphics.Color.CYAN
        strokeWidth = 12f
        strokeMiter = 10f
        strokeJoin = android.graphics.Paint.Join.ROUND
    }

    // Create a Paint that has white fill
    val textPaint = Paint().asFrameworkPaint().apply {
        isAntiAlias = true
        style = android.graphics.Paint.Style.FILL
        textSize = 100f
        color = android.graphics.Color.WHITE
    }

    // Create a canvas, draw the black stroke and
    // override it with the white fill
    Canvas(
        modifier = Modifier.fillMaxSize(),
        onDraw = {
            drawIntoCanvas {
                it.nativeCanvas.drawText(
                        "Hello World",
                        200f,
                        200.dp.toPx(),
                        textPaintStroke
                    )

                    it.nativeCanvas.drawText(
                        "Hello World",
                        200f,
                        200.dp.toPx(),
                        textPaint
                    )
                }
            }
        )
}

缺點: 這方式能繪出文字及顏色,

            但因為使用了Canvas,所以是以畫面有效區域內的座標為位置,

            無法使用Arrangement.Center,快速置中,

            必須自行算出中點扣除文字長度一半後的座標點位。

            (無法將文字當物件使用)


將上兩種方法重新整合後,出現第三種方法

@Composable
fun OutLineText(
    text: String,
    modifier: Modifier = Modifier,
    fontSize: TextUnit,
    color: Color = Color.White,
    textAlign: TextAlign = TextAlign.Start,
    outlinedBrush: Brush = Brush.horizontalGradient(
        listOf(
            Color.Blue,
            Color.Magenta,
            Color.Red,
            Color.Yellow
        )
    ),
) {
    val textLayoutResultState = remember { mutableStateOf(null) }
    Text(
        text = text,
        fontSize = fontSize,
        color = color,
        textAlign = textAlign,
        onTextLayout = { textLayoutResultState.value = it },
        modifier = modifier
            .drawWithCache {
                onDrawBehind {
                    drawIntoCanvas {
                        drawText(
                            textLayoutResultState.value!!,
                            outlinedBrush,
                            drawStyle = Stroke(
                                miter = 20f,
                                width = 15f,
                                join = StrokeJoin.Round
                            ),
                        )
                    }
                }
            }
            .width(IntrinsicSize.Max)
    )
}

draw方法有兩種,drawWithContent和drawBehind,

drawWithContent多了一個drawContent()的方法,

讓你決定文字本體的繪製順序,

則drawBehind會繪製有在文字本體之下,背景之上,


drawWithCache提供兩個方法,

onDrawWithContent和onDrawBehind,

使用方式相同,只是結果會存在Cache中,

UI重新繪製時先檢查Cache是否有相同的結果,

如果有,就不重新計算,進而增加效能。,


想了解draw方法可以參考這篇

更進階的用法可參考這篇

沒有留言:

張貼留言