·  阅读 302

## 实现思路拆分

1. 将正方形均分为4份 确定4个符号的中心点位置

``````BoxWithConstraints(modifier = modifier) {
val circleSizeDp = minOf(maxWidth, maxHeight)
val density = LocalDensity.current.density
val circleSizePx = circleSizeDp.value * density
//均分4份
val radius = circleSizePx / 4
//right 和 bottom x,y
val centerOffset = radius * 3

//加号中心点
//减号中心点
var minusOffset by remember { mutableStateOf(Offset(centerOffset, radius)) }
//乘号中心点
var timesOffset by remember { mutableStateOf(Offset(centerOffset, centerOffset)) }
//除号中心点
var divOffset by remember { mutableStateOf(Offset(radius, centerOffset)) }

}

1. 根据4个符号的中心点绘制符号
``````     //符号长度
val offset = radius / 2 + 15.dp.value
Canvas(modifier = modifier.requiredSize(size = circleSizeDp)) {
//加号
drawLine(
color = lineColor,
start = Offset(plusOffset.x - offset, plusOffset.y),
end = Offset(plusOffset.x + offset, plusOffset.y),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)

drawLine(
color = lineColor,
start = Offset(plusOffset.x, plusOffset.y - offset),
end = Offset(plusOffset.x, plusOffset.y + offset),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)

//减号
drawLine(
color = lineColor,
start = Offset(minusOffset.x - offset, minusOffset.y),
end = Offset(minusOffset.x + offset, minusOffset.y),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)
//乘号
rotate(degrees = 45F, pivot = timesOffset) {
drawLine(
color = lineColor,
start = Offset(timesOffset.x - offset, timesOffset.y),
end = Offset(timesOffset.x + offset, timesOffset.y),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)
}
rotate(degrees = 135F, pivot = timesOffset) {
drawLine(
color = lineColor,
start = Offset(timesOffset.x - offset, timesOffset.y),
end = Offset(timesOffset.x + offset, timesOffset.y),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)
}
//除号
drawLine(
color = lineColor,
start = Offset(divOffset.x - offset, divOffset.y),
end = Offset(divOffset.x + offset, divOffset.y),
strokeWidth = strokeWidth,
cap = StrokeCap.Round,
)
//除法2个圆点
drawCircle(
color = lineColor,
style = Fill,
center = Offset(divOffset.x, divOffset.y - radius / 3)
)
drawCircle(
color = lineColor,
style = Fill,
center = Offset(divOffset.x, divOffset.y + radius / 3)
)
}

1. 使用动画动起来

``````//移动长度
val animateSize = radius * 2
//记录旋转次数
var currentCount by remember { mutableStateOf(0) }
//rememberInfiniteTransition() 无限动画
val animateValue by rememberInfiniteTransition().animateFloat(
initialValue = 0f,
targetValue = animateSize,
// keyframes 分时间分段计算返回
// LinearEasing 平滑过渡
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 800
0f at 80 with LinearEasing
0.1f * animateSize at 150 with LinearEasing
0.2f * animateSize at 200 with LinearEasing
0.3f * animateSize at 250 with LinearEasing
0.4f * animateSize at 300 with LinearEasing
0.5f * animateSize at 400 with LinearEasing
0.6f * animateSize at 500 with LinearEasing
0.7f * animateSize at 600
0.8f * animateSize at 700
0.9f * animateSize at 750
animateSize at 800
},
repeatMode = RepeatMode.Restart
)
)
//监听动画结果变化 对4个断
LaunchedEffect(animateValue) {
//根据animateValue ==0 来判断 动画的每次重新执行(无奈、没有相关监听接口)
if (animateValue == 0f) {
//每次重新开始就累加1
currentCount += 1
if (currentCount > 4) {
currentCount = 1
}
}
val plus = radius + animateValue
val minus = centerOffset - animateValue
// 根据 currentCount 标记出动画运行到哪个阶段
when (currentCount) {
1 -> {//加号从左往右
minusOffset = Offset(centerOffset, plus)

timesOffset = Offset(minus, centerOffset)
}
2 -> {//加号从右往下
plusOffset = Offset(centerOffset, plus)
minusOffset = Offset(minus, centerOffset)

}
3 -> {//加号从下往左
plusOffset = Offset(minus, centerOffset)

divOffset = Offset(centerOffset, plus)
}
4 -> {

timesOffset = Offset(centerOffset, plus)
divOffset = Offset(minus, centerOffset)
}
}
}

## 扩展

``````fun Modifier.redPoint(num: String): Modifier = drawWithContent {
drawContent()
drawIntoCanvas {

val paint = Paint().apply {
color = Color.Red
}
val paintTextSize= 14.sp.toPx()
//绘制文本用FrameworkPaint
val textPaint = Paint().asFrameworkPaint().apply {
isAntiAlias = true
isDither = true
color=Color.White.toArgb()
textSize = paintTextSize
typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL)
textAlign = android.graphics.Paint.Align.CENTER
}
//测量出文本的宽度
val textWidth = textPaint.measureText(num)

//绘制背景
it.drawRoundRect(
left = size.width-offset,
top = 0f,
right = size.width,
paint = paint
)
//绘制文本
}
}

``````@Composable
fun ImageDemo() {
Image(
painter = painterResource(id = R.drawable.message),
contentDescription = "",
modifier = Modifier
.size(width = 56.dp, height = 56.dp)
.redPoint("99"),
contentScale = ContentScale.FillBounds,
alignment = Alignment.CenterEnd,
)
}

Android

Android