Android Compose 离屏缓冲 : CompositingStrategy.Offscreen
1. 前言上一篇文章 : Compose 图层的合成 : BlendMode讲了BlendMode的各种模式。比如BlendMode.DetOver会优先绘制目标图层。PreviewComposablefunMyBlendModeTest(){Box{Box(Modifier.size(100.dp).background(Color.Red,CircleShape))Box(Modifier.graphicsLayer(blendModeBlendMode.DstOver).padding(start30.dp,top30.dp).size(100.dp).background(Color.Blue,CircleShape))}}在图形绘制的概念里source : 源图形 蓝色圆destination : 目标图形 背景 红色圆但是如果我们给外层的Box添加一个背景PreviewComposablefunMyBlendModeTest(){Box(Modifier.background(Color.DarkGray)){Box(Modifier.size(100.dp).background(Color.Red,CircleShape))Box(Modifier.graphicsLayer(blendModeBlendMode.DstOver).padding(start30.dp,top30.dp).size(100.dp).background(Color.Blue,CircleShape))}}可以发现蓝色圆(目标图层)直接不见了。为什么呢因为背景的这个颜色也属于源图层把蓝色圆给盖住了。如果我们想让蓝色圆被红色圆盖住我们就需要把红色圆先拿起来让蓝色圆先合红色圆融合后再贴到灰色的这个背景上。要怎么做呢 ? 这就要用到离屏缓冲了。2.1 什么是离屏缓冲离屏缓冲 一块不在屏幕上显示的临时画布 / 纹理。正常绘制直接往屏幕的 “前台缓冲区” 画 → 画完直接显示。离屏绘制先开辟一块屏幕外的缓冲区FBO / 纹理把复杂内容 / 特效圆角、阴影、模糊、BlendMode 叠加全部画到这块临时缓冲最后把整个缓冲一次性贴到屏幕上2.2 怎么实现离屏缓冲在背景层里面两个圆的外面再包裹一层Box并使用Modifier.graphicsLayer(compositingStrategy CompositingStrategy.Offscreen)PreviewComposablefunMyBlendModeTest(){Box(Modifier.background(Color.DarkGray)){Box(Modifier.graphicsLayer(compositingStrategyCompositingStrategy.Offscreen)){Box(Modifier.size(100.dp).background(Color.Red,CircleShape))Box(Modifier.graphicsLayer(blendModeBlendMode.DstOver).padding(start30.dp,top30.dp).size(100.dp).background(Color.Blue,CircleShape))}}}BlendMode.DstOver虽然可以单独使用但是实际使用中通常要配合CompositingStrategy.Offscreen来使用的。2.3 Compose可能自动使用离屏缓冲我们在使用Modifier.alpha(0.5f)的时候Compose内部其实就是使用离屏缓冲来实现的。会先在缓冲区画一个不透明的红色圆然后又在红色圆上面画了一个不透明的蓝色圆。然后用这个融合的结果都用50%的透明度画到了这个灰色的背景上。PreviewComposablefunAlphaTest(){Box(Modifier.background(Color.DarkGray)){Box(Modifier.alpha(0.5f)){Box(Modifier.size(100.dp).background(Color.Red,CircleShape))Box(Modifier.padding(start30.dp,top30.dp).size(100.dp).background(Color.Blue,CircleShape))}}}还有设置了 RenderEffect高斯模糊、圆角等→ 也会自动离屏使用graphicsLayer(alpha 0.5f, compositingStrategy CompositingStrategy.ModulateAlpha)可以强制不开启离屏显示绝大多数情况下都用不到。2.4 自定义绘制里的使用离屏缓冲Canvas必须要设置.graphicsLayer(compositingStrategy CompositingStrategy.Offscreen)离屏缓冲才会生效。PreviewComposablefunCanvasTest(){Canvas(Modifier.size(100.dp).graphicsLayer(compositingStrategyCompositingStrategy.Offscreen)){drawCircle(Color.Red,size.width/3,Offset(size.width/3f,size.height/3f))drawCircle(Color.Blue,size.width/3,Offset(size.width/3f*2,size.height/3f*2),blendModeBlendMode.SrcOut)}}有一点需要注意的是在自定义绘制的时候它的区域计算和在组件中使用Modifier.graphicsLayer(blendMode ...)有点不一样它看的不是整个DrawScope的区域而是源图形的区域。在组件中使用Modifier.graphicsLayer(blendMode BlendMode.SrcOut)会将红色圆全部擦掉而自定义绘制中这个红色圆的大部分还是在的因为自定义绘制中它的区域计算只是这个蓝色的圆的区域。