代码现实了可拖拽的数字角标,拖动距离大于某个数值时丢弃(清理未读内容)
//将方法放在Modifier类上,就可以在全局任意位置使用
//以下注释假设传入的tag:Int为25
fun Modifier.unread(offset: Offset, tag: Int): Modifier = this.drawBehind {
if(tag > 0) { //数字小于1时,表示没有未读消息,不显示
val badgeSize = 16.dp.toPx() // 角标的大小
val badgeOffset = Offset(x = size.width, y = 0f) // 相对于父元素的位置(右上角)
val fontSize = 10.sp // 文字大小
// 绘制红色的圆形角标背景
drawCircle(
color = Color.Red,
radius = badgeSize / 2,
center = badgeOffset+offset
)
// 绘制数字
val text = tag.toString() //将数字转成String
val textPaint = android.graphics.Paint().apply {
textSize = fontSize.toPx()
color = android.graphics.Color.WHITE
}
/*
* 创建一个float数组,用于接收每一个字符显示时所占宽度
* 如果都是单字节符号,比如:数字、字母,那么每个索引都应该会是同样的小数
* 可如果有中文,那么宽度会不一样
* */
val widths = FloatArray(text.length)
textPaint.getTextWidths(text, widths) //执行完后,widths = [20.0, 20.0]
val textWidth = (text.length * widths[0]) / 2 //因为每个字符都是数字所以宽度一样,所以随便取一个就可以了。得出文字总宽度/2
val y = (badgeSize - fontSize.toPx())/2
drawContext.canvas.nativeCanvas.drawText(
text,
badgeOffset.x-textWidth+offset.x, //由于角标圆形背景的位置是中心点位置,所以文字的x要减去文字总宽度的一半
badgeOffset.y+y+offset.y,
textPaint
)
}
}
var pointerOffset by remember {
mutableStateOf(Offset(0f, 0f))
}
//item.tag是一个State,记录角标的数字
Icon(imageVector = if(selected) item.selectedIcon else item.defaultIcon, contentDescription = item.title, tint = bottomBar.value, modifier = Modifier.pointerInput("draging") {
detectDragGestures(onDragEnd = {
if(abs(pointerOffset.x)+abs(pointerOffset.y)>800) {
item.tag = 0 //移动距离大于800时清除角标
}
pointerOffset = Offset(0f, 0f) //拖动结束,将偏移归0
}) { _, dragAmount ->
pointerOffset += dragAmount
}
}
.unread(pointerOffset, item.tag))