注册
web

[compose] 仿刮刮乐效果

需求


下班路上新开了一家彩-票店,路过时总是心痒,本着小D怡情的心态,偶尔去刮几张,可是随着时间久了,发现也花了不少钱,看网上有人开发电子木鱼,突然奇想,为什么不做一张电子彩-票。


分析


传统View,网上有很多解决方案,大多数是通过混合模式进行两个图层的合并。


大致思路:

1、使用onDraw()方法中的Canvas绘制底层中奖层

2、在上面绘制一个蒙版层Bitmap, 在蒙版层Bitmap里面,放置一个新的Canvas

3、绘制一个灰色的矩阵,绘制一个path,将paint的Xfermode设置为 PorterDuff.Mode.DST_IN
4、手指移动时,更新Path路径


Compose实现

1、通过实现DrawModifier,重写draw() 方法

2、绘制原始内容层,drawContent()
3、绘制蒙版和手势层,


//配置画笔 blendMode = Xfermode
private val pathPaint = Paint().apply {
alpha = 0f
style = PaintingStyle.Stroke
strokeWidth = 70f
blendMode = BlendMode.SrcIn
strokeJoin = StrokeJoin.Round
strokeCap = StrokeCap.Round
}

drawIntoCanvas {
//设置画布大小尺寸
val rect = Rect(0f, 0f, size.width, size.height)
//从原始画布层,转换一个新的画布层
it.saveLayer(rect, layerPaint)
//设置新画布大小尺寸
it.drawRect(rect, layerPaint)
startPath.lineTo(moveOffset.x, moveOffset.y)
//绘制手指移动path
it.drawPath(startPath, pathPaint)
it.restore()
}

完整代码


fun ScrapeLayePage(){
var linePath by remember { mutableStateOf(Offset.Zero) }
val path by remember { mutableStateOf(Path()) }
Column(modifier = Modifier
.fillMaxWidth()
.pointerInput("dragging") {
awaitEachGesture {
while (true) {
val event = awaitPointerEvent()
when (event.type) {
//按住时,更新起始点
Press -> {
path.moveTo(
event.changes.first().position.x,
event.changes.first().position.y
)
}
//移动时,更新起始点 移动时,记录路径path
Move -> {
linePath = event.changes.first().position
}
}
}
}
}
.scrapeLayer(path, linePath)
) {
Image(
modifier = Modifier.fillMaxWidth(),
painter = painterResource(id = R.mipmap.cat),
contentDescription = ""
)
Text(text = "这是一只可爱的猫咪~~")
}
}

fun Modifier.scrapeLayer(startPath: Path, moveOffset: Offset) =
this.then(ScrapeLayer(startPath, moveOffset))

class ScrapeLayer(private val startPath: Path, private val moveOffset: Offset) : DrawModifier {

private val pathPaint = Paint().apply {
alpha = 0f
style = PaintingStyle.Stroke
strokeWidth = 70f
blendMode = BlendMode.SrcIn
strokeJoin = StrokeJoin.Round
strokeCap = StrokeCap.Round
}

private val layerPaint = Paint().apply {
color = Color.Gray
}

override fun ContentDrawScope.draw() {
drawContent()
drawIntoCanvas {
val rect = Rect(0f, 0f, size.width, size.height)
//从当前画布,裁切一个新的图层
it.saveLayer(rect, layerPaint)
it.drawRect(rect, layerPaint)
startPath.lineTo(moveOffset.x, moveOffset.y)
it.drawPath(startPath, pathPaint)
it.restore()
}
}
}

图片.png

参考资料



作者:Gx
来源:juejin.cn/post/7303075105390133259

0 个评论

要回复文章请先登录注册