为什么compose-intro-showcase能在UI上“挖出“聚光灯:BlendMode.Xor与Canvas实现原理全解析

发布时间:2026/8/27 17:25:33
为什么compose-intro-showcase能在UI上“挖出“聚光灯:BlendMode.Xor与Canvas实现原理全解析 为什么compose-intro-showcase能在UI上挖出聚光灯BlendMode.Xor与Canvas实现原理全解析【免费下载链接】compose-intro-showcaseAndroid - Highlight different features of the app using Jetpack Compose项目地址: https://gitcode.com/gh_mirrors/co/compose-intro-showcasecompose-intro-showcase 是一个基于 Jetpack Compose 的 Android 开源库专门用于在高德地图上式地高亮App 中的某个控件它先铺一层半透明黑色遮罩再在目标位置挖出一个透明圆洞形成经典的聚光灯引导效果Intro Showcase。它的核心魔法只有两样一块铺满全屏的Canvas和一行BlendMode.Xor的混合模式。聚光灯效果长什么样Intro Showcase 是什么当你第一次打开一个 App扫一扫在这里收藏按钮在这里之类的提示气泡就会出现在关键功能旁边同时周围界面被压暗——这个效果就是 Material 设计指南中的 Intro Showcase。compose-intro-showcase 聚光灯效果示意图黑色遮罩中被挖出透明圆洞突出目标控件传统 View 体系里大家常用 TapTargetView 实现类似效果而 compose-intro-showcase 用纯 Compose 重写了它并且让聚光灯能够覆盖整个 App 窗口不只是当前 Composable 内部。实现原理全解析一个窗口、一块 Canvas、三种圆圈整个实现由三个文件协作完成阅读顺序建议如下窗口层showcase/src/main/java/com/canopas/lib/showcase/component/ShowcaseComposeView.kt绘制层showcase/src/main/java/com/canopas/lib/showcase/component/ShowcaseContent.ktAPI 层showcase/src/main/java/com/canopas/lib/showcase/IntroShowcase.kt第一步用独立窗口盖住整个界面如果只在 Compose 的Box里画遮罩聚光灯最多只能覆盖当前页面的一小块。ShowcaseComposeView的做法更彻底——它继承AbstractComposeView并通过WindowManager以TYPE_APPLICATION_PANEL类型添加了一个MATCH_PARENT 的独立窗口参数还设置了PixelFormat.TRANSLUCENT半透明像素格式保证圆洞以外的区域是真透明而不是黑色。关键点这是一个悬浮在整个 Activity 之上的全新窗口所以聚光灯能盖住状态栏下方的全部内容。第二步Canvas 画背景大圆和脉冲光环绘制集中在ShowcaseContent.kt的Canvas中绘制顺序是背景大圆drawCircle先画一个覆盖目标控件 描述文字卡片的超大黑色圆半径由getOuterRadius用勾股定理算出对角线的一半这是聚光灯的暗色幕布脉冲光环两个错开 1 秒启动的Animatable各自以 2 秒循环从 0 涨到目标尺寸并淡出形成目标圆周围一圈圈向外扩散的涟漪Xor 挖洞圆最后再画一个半径为目标最大边长 / 2 40f的圆——注意它带着blendMode BlendMode.Xor这就是挖洞的一刀。第三步BlendMode.Xor 挖出透明圆洞BlendMode.Xor是全部秘密所在。XOR异或的位运算规则非常简单遮罩像素圆圈像素Xor 结果110抵消透明101保留011保留000翻译成人话只有一黑一白重叠的地方才会被擦掉。背景大圆盖住了目标区域再用 Xor 画目标圆两者重叠的交集刚好从黑色幕布上被擦除露出下面真实的 App 界面——透明圆洞就出现了而无需任何橡皮擦或裁剪路径。✨顺带一提源码里有个隐藏彩蛋Canvas 上加了graphicsLayer(alpha 0.99f)。把透明度设为 0.99 是为了强制合成器走特定的绘制管线保证 Xor 混合结果不被窗口合成抹平属于实战中踩坑总结出来的小技巧。细节彩蛋描述卡片如何始终被圆圈包住引导文字的位置是动态的ShowCaseText先测量自己若目标上方放得下就放上方否则放下方。文字落位后getOuterRect会取文字矩形 ∪ 目标矩形的外接框再算出能同时包住两者的圆心和半径赋给背景大圆——这就是为什么黑幕永远恰好盖住目标 文案两块内容不多不少。快速上手三步在 App 中启用聚光灯引导获取代码执行git clone https://gitcode.com/gh_mirrors/co/compose-intro-showcase也可从 Maven Central 引入com.canopas.intro-showcase-view:introshowcaseview:2.0.0标记目标用Modifier.introShowCaseTarget(index, style, content)给任意 Composable 打上序号标签API 定义见 IntroShowcase.kt启动引导调用IntroShowcase(showIntroShowCase true, onShowCaseCompleted {...})用户点击目标圆洞后即可切换到下一个序号全部完成后触发回调。新手常见问题 FAQ为什么不用裁剪clip路径挖洞Xor 混合天然只作用于两图形交集且对任意形状都成立比ClipPath手动算路径更简单也省去了坐标同步的问题。背景透明度、颜色可以改吗可以。ShowcaseStyle提供backgroundColor、backgroundAlpha默认 0.9、targetCircleColor三个参数每个目标都可以单独定制。点击圆洞内会怎样pointerInput中做了targetRect.contains(tapOffset)判断点在中空区域会推进到下一个引导步骤点其他位置则按dismissOnClickOutside参数决定是否关闭。想自己动手翻源码重点看ShowcaseContent.kt中从Canvas { ... }到drawCircle(..., blendMode BlendMode.Xor)的那段绘制逻辑不到 50 行就包含了全部原理。【免费下载链接】compose-intro-showcaseAndroid - Highlight different features of the app using Jetpack Compose项目地址: https://gitcode.com/gh_mirrors/co/compose-intro-showcase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考