解决这一问题需要简单的数学计算,带旋转的Drawcope,测量文本宽度和高度的TextMeasurer.和合成修饰语,如果你想把它们作为修饰语.构建了一个具有坚实的背景,另一个具有微光效果.在应用这些修饰符之前,可以判断painter.State是否为成功.
结果
修饰符实现
fun Modifier.drawDiagonalLabel(
text: String,
color: Color,
style: TextStyle = TextStyle(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold,
color = Color.White
),
labelTextRatio: Float = 7f
) = composed(
factory = {
val textMeasurer = rememberTextMeasurer()
val textLayout结果: TextLayout结果 = remember {
textMeasurer.measure(text = AnnotatedString(text), style = style)
}
Modifier
.clipToBounds()
.drawWithContent {
val canvasWidth = size.width
val canvasHeight = size.height
val textSize = textLayout结果.size
val textWidth = textSize.width
val textHeight = textSize.height
val rectWidth = textWidth * labelTextRatio
val rectHeight = textHeight * 1.1f
val rect = Rect(
offset = Offset(canvasWidth - rectWidth, 0f),
size = Size(rectWidth, rectHeight)
)
val sqrt = sqrt(rectWidth / 2f)
val translatePos = sqrt * sqrt
drawContent()
withTransform(
{
rotate(
degrees = 45f,
pivot = Offset(
canvasWidth - rectWidth / 2,
translatePos
)
)
}
) {
drawRect(
color = color,
topLeft = rect.topLeft,
size = rect.size
)
drawText(
textMeasurer = textMeasurer,
text = text,
style = style,
topLeft = Offset(
rect.left + (rectWidth - textWidth) / 2f,
rect.top + (rect.bottom - textHeight) / 2f
)
)
}
}
}
)
fun Modifier.drawDiagonalShimmerLabel(
text: String,
color: Color,
style: TextStyle = TextStyle(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold,
color = Color.White
),
labelTextRatio: Float = 7f,
) = composed(
factory = {
val textMeasurer = rememberTextMeasurer()
val textLayout结果: TextLayout结果 = remember {
textMeasurer.measure(text = AnnotatedString(text), style = style)
}
val transition = rememberInfiniteTransition()
val progress by transition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(3000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Modifier
.clipToBounds()
.drawWithContent {
val canvasWidth = size.width
val canvasHeight = size.height
val textSize = textLayout结果.size
val textWidth = textSize.width
val textHeight = textSize.height
val rectWidth = textWidth * labelTextRatio
val rectHeight = textHeight * 1.1f
val rect = Rect(
offset = Offset(canvasWidth - rectWidth, 0f),
size = Size(rectWidth, rectHeight)
)
val sqrt = sqrt(rectWidth / 2f)
val translatePos = sqrt * sqrt
val brush = Brush.linearGradient(
colors = listOf(
color,
style.color,
color,
),
start = Offset(progress * canvasWidth, progress * canvasHeight),
end = Offset(
x = progress * canvasWidth + rectHeight,
y = progress * canvasHeight + rectHeight
),
)
drawContent()
withTransform(
{
rotate(
degrees = 45f,
pivot = Offset(
canvasWidth - rectWidth / 2,
translatePos
)
)
}
) {
drawRect(
brush = brush,
topLeft = rect.topLeft,
size = rect.size
)
drawText(
textMeasurer = textMeasurer,
text = text,
style = style,
topLeft = Offset(
rect.left + (rectWidth - textWidth) / 2f,
rect.top + (rect.bottom - textHeight) / 2f
)
)
}
}
}
)
用法
Column(
modifier = Modifier
.background(backgroundColor)
.fillMaxSize()
.padding(20.dp)
) {
val painter1 = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data("https://www.techtoyreviews.com/wp-content/uploads/2020/09/5152094_Cover_PS5.jpg")
.size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
.build()
)
Image(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(4 / 3f)
.then(
if (painter1.state is AsyncImagePainter.State.Success) {
Modifier.drawDiagonalLabel(
text = "50%",
color = Color.Red
)
} else Modifier
),
painter = painter1,
contentScale = ContentScale.FillBounds,
contentDescription = null
)
Spacer(modifier = Modifier.height(10.dp))
val painter2 = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data("https://i02.appmifile.com/images/2019/06/03/03ab1861-42fe-4137-b7df-2840d9d3a7f5.png")
.size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
.build()
)
Image(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(4 / 3f)
.then(
if (painter2.state is AsyncImagePainter.State.Success) {
Modifier.drawDiagonalShimmerLabel(
text = "40% OFF",
color = Color(0xff4CAF50),
labelTextRatio = 5f
)
} else Modifier
),
painter = painter2,
contentScale = ContentScale.FillBounds,
contentDescription = null
)
}
@Composable
private fun RibbonSample() {
val text = "50%"
val textMeasurer = rememberTextMeasurer()
val style = TextStyle(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold,
color = Color.White
)
val textLayout结果: TextLayout结果 = remember {
textMeasurer.measure(text = AnnotatedString(text), style = style)
}
Box(
modifier = Modifier
.clipToBounds()
.drawWithContent {
val canvasWidth = size.width
val textSize = textLayout结果.size
val textWidth = textSize.width
val textHeight = textSize.height
val rectWidth = textWidth * 7f
val rectHeight = textHeight * 1.1f
val rect = Rect(
offset = Offset(canvasWidth - rectWidth, 0f),
size = Size(rectWidth, rectHeight)
)
val translatePos = sqrt(rectWidth / 2f) * sqrt(rectWidth / 2f)
drawContent()
withTransform(
{
rotate(
degrees = 45f,
pivot = Offset(
canvasWidth - rectWidth / 2,
translatePos
)
)
}
) {
drawRect(
Color.Red,
topLeft = rect.topLeft,
size = rect.size
)
drawText(
textMeasurer = textMeasurer,
text = text,
style = style,
topLeft = Offset(
rect.left + (rectWidth - textWidth) / 2f,
rect.top + (rect.bottom - textHeight) / 2f
)
)
}
}
) {
Image(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(4 / 3f),
painter = painterResource(id = R.drawable.landscape1),
contentScale = ContentScale.FillBounds,
contentDescription = null
)
}
}