React Native Skia Group 组件完全指南:Paint 继承、变换、裁剪、图层效果与 zIndex
发布时间:2026/9/25 6:01:21来源:尧图网络
图形学移动开发跨平台UI组件【免费下载链接】react-native-skiaHigh-performance React Native Graphics using Skia项目地址https://gitcode.com/gh_mirrors/re/react-native-skia点击查看免费下载Group是 React Native Skia 中最重要的组合composition原语它可以被任意深度嵌套并统一向其所有子元素施加 Paint 属性、坐标变换、裁剪区域与图层效果。本文以官方文档 group.md 为主线结合仓库源码与测试用例完整讲解 Group 的每个属性transform、matrix、origin、clip、invertClip、layer、zIndex以及基于 Group 实现的FitBox组件读完你将能熟练使用 Group 实现批量绘制控制、局部裁剪、离屏特效和可控的绘制顺序。Group 组件概览与属性总表Group 组件是 React Native Skia 中一个不可或缺的构造单元组件之间可以互相深度嵌套。它能够对子元素children施加以下四类操作Paint 属性Paint Properties颜色、描边样式等绘制属性向下继承变换Transformations平移、旋转、缩放、倾斜等坐标变换裁剪操作Clipping Operations限制子元素的可见区域图层效果Layer Effects将子元素整体栅格化为位图并应用特效。在类型层面Group 的属性由GroupProps定义见 Common.ts它同时继承了PaintProps所有绘制属性与CTMProps变换、裁剪、图层属性并额外提供zIndexexport interface GroupProps extends PaintProps, CTMProps { zIndex?: number; }官方文档给出的完整属性表如下名称类型说明transform?Transform2d与 React Native 的 transform API 一致但有两点差异变换默认原点位于左上角React Native 视图默认在中心所有旋转角度均以弧度radians为单位。matrix?InputMatrix应用于 Group 的矩阵。当同时提供matrix和transform时matrix优先。origin?Point设置变换的原点。该属性不会被其子元素继承。clip?RectOrRRectOrPath用于裁剪子元素的矩形、圆角矩形或 Path。invertClip?boolean反转裁剪区域裁剪区域之外的部分显示内部的部分隐藏。layer?RefObjectPaint将子元素作为位图绘制并应用该 Paint 提供的效果。zIndex?number覆盖子元素的绘制顺序。zIndex 更高的子元素绘制在更低的之上作用域局限于当前 Group默认值为 0支持负值。InputMatrix的实际类型可从 Matrix.ts 看到它接受SkMatrix、Matrix3、Matrix4或扁平的number[]数组为命令式矩阵留出了灵活的传参空间。不受 Group 属性影响的组件以下三种组件不会受到 Group 属性例如 Group 上设置的 Paint 属性的影响。如果需要对它们应用绘制效果必须借助layer 效果将 Group 的layer属性与Paint结合使用Picture通过 layer 效果应用绘制效果的说明见其文档SVGSVG 图像同样需要用 layer 来应用效果Paragraph文本段落组件的特效应用方式一致。也就是说Group 上设置的color、style等 Paint 属性不会穿透到 Picture / SVG / Paragraph 这类自包含的组件内部。Paint 属性向子元素继承绘制状态Group 的子元素会继承施加在 Group 上的所有 Paint 属性。这些属性既可以是color、style这类普通属性也可以是以子组件形式声明的Shader /、ImageFilter /、ColorMatrix /等完整绘制体系见 paint 文档。下面的示例中Group设置colorlightblue与stylestroke strokeWidth{10}内部两个圆都会继承该描边样式其中右侧的圆用自己的colorwhite覆盖了填充色import { Canvas, Circle, Group } from shopify/react-native-skia; export const PaintDemo () { const r 128; return ( Canvas style{{ flex: 1 }} Circle cx{r} cy{r} r{r} color#51AFED / {/* 绘制属性会被下述同级 Group 及其后代继承。 */} Group colorlightblue stylestroke strokeWidth{10} Circle cx{r} cy{r} r{r / 2} / Circle cx{r} cy{r} r{r / 3} colorwhite / /Group /Canvas ); };从类型上看PaintProps定义了color、strokeWidth、blendMode、stylefill/stroke、strokeJoin、strokeCap、strokeMiter、opacity、antiAlias、dither等全部可继承属性见 Common.ts这解释了为什么Group 上能写的绘制属性与普通绘制组件完全一致——它们共享同一份属性类型。Transformations与 React Native 的两点关键差异Group 的transform属性与 React Native 中的同名属性几乎一致但有一个显著差异在 React Native 中变换的原点是对象的中心而在 Skia 中变换原点位于对象的左上角。与之配套的origin属性是一个便捷辅助项用于显式设置变换的原点。注意origin不会被其子元素继承所有旋转角度都以弧度为单位例如Math.PI / 6表示 30 度。简单变换在下面的例子中Group 对内部的圆角矩形施加了skewX水平倾斜变换import { Canvas, Fill, Group, RoundedRect } from shopify/react-native-skia; const SimpleTransform () { return ( Canvas style{{ flex: 1 }} Fill color#e8f4f8 / Group colorlightblue transform{[{ skewX: Math.PI / 6 }]} RoundedRect x{64} y{64} width{128} height{128} r{10} / /Group /Canvas ); };通过 origin 变换原点通过origin{{ x: 128, y: 128 }}把变换原点移到矩形的中心后同样的skewX会围绕新原点进行import { Canvas, Fill, Group, RoundedRect } from shopify/react-native-skia; const SimpleTransform () { return ( Canvas style{{ flex: 1 }} Fill color#e8f4f8 / Group colorlightblue origin{{ x: 128, y: 128 }} transform{[{ skewX: Math.PI / 6 }]} RoundedRect x{64} y{64} width{128} height{128} r{10} / /Group /Canvas ); };命令式矩阵Skia.Matrix()当 API 期望一个矩阵、或需要以命令式方式构造变换时可以使用Skia.Matrix()。它会创建一个单位矩阵identity matrix其变换方法会就地修改矩阵本身、返回同一个矩阵以便链式调用并按调用顺序将每次操作**前拼接pre-concatenate**到当前矩阵上。旋转角度以弧度为单位。import { Canvas, Group, RoundedRect, Skia, } from shopify/react-native-skia; const center { x: 128, y: 128 }; const matrix Skia.Matrix() .translate(center.x, center.y) .rotate(Math.PI / 6) .scale(1.2, 1.2) .translate(-center.x, -center.y); const ImperativeMatrix () ( Canvas style{{ flex: 1 }} Group matrix{matrix} RoundedRect x{64} y{64} width{128} height{128} r{10} colorlightblue / /Group /Canvas );上述示例通过在中心平移 → 旋转 → 缩放 → 平移回原点的调用顺序等效于绕中心旋转 30 度并放大 1.2 倍。SkMatrix接口见 Matrix.ts公开了以下可用的变换操作前拼接pre-concatenatetranslate(x, y)、scale(x, y?)、skew(x, y)、rotate(theta)、concat(matrix)——这些方法把变换拼接在当前矩阵的前面后拼接post-concatenatepostTranslate()、postScale()、postSkew()、postRotate()——把变换拼接在当前矩阵的另一侧。在pre与post之间切换会改变运算顺序进而得到不同的组合结果工具方法identity()将矩阵重置为单位矩阵get()返回矩阵的 9 个数值项。矩阵 origin 的注意事项origin属性也可以为传入 Group 的矩阵移动变换原点。注意避免同时在矩阵内和通过origin属性施加同一个原点否则原点会被应用两次。origin的作用域局限于当前 Group且不会被其子元素继承。源码中matrix/transform/origin的组合顺序由processTransformProps精确实现见 Transform.tsconst { transform, origin, matrix } props; if (matrix) { if (origin) { m3.translate(origin.x, origin.y); m3.concat(matrix); m3.translate(-origin.x, -origin.y); } else { m3.concat(matrix); } } else if (transform) { if (origin) { m3.translate(origin.x, origin.y); } processTransform(m3, transform); if (origin) { m3.translate(-origin.x, -origin.y); } }可以看到无论matrix还是transformorigin都是通过先平移到原点、执行变换、再平移回来的三步包装实现的同时matrix分支优先于transform分支这正是文档中同时提供两者时matrix优先的底层原因。processTransform2d()从 transform 数组构造矩阵processTransform2d()是一个便捷替代方案它接收与transform属性完全相同的有序 transform 数组语法并返回一个新矩阵内部实现见 Matrix.ts即processTransform(Skia.Matrix(), transforms)import { Canvas, Group, RoundedRect, processTransform2d, } from shopify/react-native-skia; const center { x: 128, y: 128 }; const matrix processTransform2d([ { translate: [center.x, center.y] }, { rotate: Math.PI / 6 }, { scale: 1.2 }, { translate: [-center.x, -center.y] }, ]); const ProcessedMatrix () ( Canvas style{{ flex: 1 }} Group matrix{matrix} RoundedRect x{64} y{64} width{128} height{128} r{10} colorlightblue / /Group /Canvas );动画化变换历史示例中可能提到的一些计算值computed value辅助函数已不在当前 API 中。对于动画化的变换应使用 Reanimated 的 Shared Value 直接作为属性传入无需createAnimatedComponent或useAnimatedProps具体说明见 animations 文档。例如const r useSharedValue(0); const c useDerivedValue(() size - r.value); // ... Group blendModemultiply Circle cx{r} cy{r} r{r} colorcyan / /GroupClipping Operations裁剪子元素的可见区域clip提供一个裁剪区域用于决定子元素中哪些部分应被显示区域内部显示区域外部隐藏。当使用invertClip时逻辑反转区域外部显示区域内部隐藏。clip的类型ClipDef在源码中定义为SkRRect | SkRect | PathDef见 Common.ts其中PathDef既可以是 SVG 路径字符串也可以是SkPath对象。裁剪矩形Clip Rectangle用rect(x, y, width, height)构造矩形只显示矩形内部区域的图片内容import { Canvas, Group, Image, useImage, rect, Fill, } from shopify/react-native-skia; const size 256; const padding 32; const Clip () { const image useImage(require(./assets/oslo.jpg)); const rct rect(padding, padding, size - padding * 2, size - padding * 2); return ( Canvas style{{ flex: 1 }} Fill colorlightblue / Group clip{rct} Image image{image} x{0} y{0} width{size} height{size} fitcover / /Group /Canvas ); };裁剪圆角矩形Clip Rounded Rectangle用rrect(rect, rx, ry)构造带圆角的裁剪区域圆角半径为rimport { Canvas, Group, Image, useImage, rrect, rect, } from shopify/react-native-skia; const size 256; const padding 32; const r 8; const Clip () { const image useImage(require(./assets/oslo.jpg)); const roundedRect rrect( rect(padding, padding, size - padding * 2, size - padding * 2), r, r ); return ( Canvas style{{ flex: 1 }} Group clip{roundedRect} Image image{image} x{0} y{0} width{size} height{size} fitcover / /Group /Canvas ); };裁剪路径Clip Path用Skia.Path.MakeFromSVGString()从 SVG 路径字符串创建五角星路径并作为裁剪区域import { Canvas, Group, Image, useImage, Skia, } from shopify/react-native-skia; const Clip () { const image useImage(require(./assets/oslo.jpg)); const star Skia.Path.MakeFromSVGString( M 128 0 L 168 80 L 256 93 L 192 155 L 207 244 L 128 202 L 49 244 L 64 155 L 0 93 L 88 80 L 128 0 Z )!; return ( Canvas style{{ flex: 1 }} Group clip{star} Image image{image} x{0} y{0} width{256} height{256} fitcover / /Group /Canvas ); };反转裁剪Invert Clip在同一个五角星路径上添加invertClip可见区域完全反转——只显示五角星之外的部分import { Canvas, Group, Image, useImage, Skia, } from shopify/react-native-skia; const Clip () { const image useImage(require(./assets/oslo.jpg)); const star Skia.Path.MakeFromSVGString( M 128 0 L 168 80 L 256 93 L 192 155 L 207 244 L 128 202 L 49 244 L 64 155 L 0 93 L 88 80 L 128 0 Z )!; return ( Canvas style{{ flex: 1 }} Group clip{star} invertClip Image image{image} x{0} y{0} width{256} height{256} fitcover / /Group /Canvas ); };上述矩形、圆角矩形、路径与反转裁剪四个场景均有对应的快照测试见 documentation/Group.spec.tsx 与 e2e/Group.spec.tsx测试用oslo.jpg图片绘制后与group/clip-*.png基准快照比对可作实现一致性的验证依据。Layer Effects离屏栅格化与应用特效使用layer属性会在内部创建一个位图先将子元素绘制栅格化到该位图上再应用由 Paint 提供的效果。这对于构建需要作用于一组元素整体而非单个元素的效果尤为有用——例如对一个 Group 内的所有图形统一做模糊再叠加颜色矩阵调色import { Canvas, Group, Circle, Blur, Paint, ColorMatrix, } from shopify/react-native-skia; const Clip () { return ( Canvas style{{ flex: 1 }} Group colorlightblue layer{ Paint Blur blur{20} / ColorMatrix matrix{[ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 18, -7, ]} / /Paint } Circle cx{0} cy{128} r{128 * 0.95} / Circle cx{256} cy{128} r{128 * 0.95} / /Group /Canvas ); };从组件实现看layer接受两种形态见 Group.tsx当layer是有效的 React 元素例如Paint及其子效果时Group 会被拆分为skLayer{layer}skGroup {...props} //skLayer先渲染图层再渲染内容当layer是SkPaint引用或布尔值时则直接作为skGroup的layer属性传递。CTMProps.layer的类型定义为SkPaint | boolean见 Common.ts对应 Skia 底层saveLayer语义。该场景同样有快照测试覆盖见 documentation/Group.spec.tsx对应基准图group/rasterize.png。Drawing Order (zIndex)控制绘制顺序zIndex属性允许你控制元素的绘制顺序可应用于Group 或任何绘制命令。zIndex 更高的元素会绘制在 zIndex 更低的兄弟元素之上。默认 zIndex 为 0支持负值。zIndex的作用域局限于其父级Group /之内一个元素的 zIndex 只影响它与同一 Group 内兄弟元素的相对绘制顺序而一个 Group 的 zIndex 则决定该 Group 在它的兄弟 Group 之间的顺序。示例下面例子中青色圆zIndex{2}绘制在最上层其次是品红圆zIndex{1}最后是黄色圆zIndex{0}import { Canvas, Circle, Group, BlurMask } from shopify/react-native-skia; export const ZIndexDemo () { const r 80; const width 256; const height 256; return ( Canvas style{{ width, height }} Group BlurMask stylesolid blur{10} / Circle cx{r} cy{r} r{r} colorcyan zIndex{2} / Circle cx{width - r} cy{r} r{r} colormagenta zIndex{1} / Circle cx{width / 2} cy{height - r} r{r} coloryellow zIndex{0} / /Group /Canvas ); };zIndex 的行为在端到端测试中有全面覆盖见 e2e/Drawings.spec.tsx包括常规正 zIndex 排序zIndex.png嵌套BlurMask下 zIndex 依然生效zIndex2.png负 zIndex参与排序zIndex-negative.png青色zIndex{-1}垫底混合正负 zIndexzIndex-mixed.png含10与-5Paint 上下文保持即使元素设置了 zIndex 被重排它仍然能从 Group 的 Paint 上下文中继承颜色zIndex-paint.png。FitBox基于 Group 的自动缩放适配FitBox组件基于Group实现能够将一组绘制内容自动缩放以适配目标矩形。它的本质是在挂载时根据src、dst和fit计算出一个 transform 矩阵然后交给Group应用见 FitBox.tsxexport const FitBox ({ fit contain, src, dst, children }: FitProps) { const transform useMemo(() fitbox(fit, src, dst), [dst, fit, src]); return Group transform{transform}{children}/Group; };属性表名称类型说明srcSKRect缩放前绘制的包围矩形bounding rectangledstSKRect缩放后绘制的目标包围矩形fit?Fit使绘制内容适配矩形的方法。可选值contain、fill、cover、fitHeight、fitWidth、scaleDown、none默认值为containFit联合类型与文档完全一致见 Common.ts。示例假设有一份 SVG 导出内容其包围源矩形为0, 0, 664, 308svg width664 height308 viewBox0 0 664 308 fillnone xmlnshttp://www.w3.org/2000/svg path dM 170.1 215.5 C 165 222.3... fillblack/ /svg我们希望把这个路径自动缩放到256 x 256的画布中import { Canvas, FitBox, Path, rect } from shopify/react-native-skia; const Hello () { return ( Canvas style{{ width: 256, height: 256 }} FitBox src{rect(0, 0, 664, 308)} dst{rect(0, 0, 256, 256)} Path pathM 170.1 215.5 C 165 222.3... strokeCapround strokeJoinround stylestroke strokeWidth{30} / /FitBox /Canvas ); };底层实现fitRects 与 rect2rectFitBox的核心算法位于 Fitting.tsrect2rect(src, dst)将源矩形映射到目标矩形等价于按顺序执行translateX、translateY、scaleX、scaleY四个变换const scaleX dst.width / src.width; const scaleY dst.height / src.height; const translateX dst.x - src.x * scaleX; const translateY dst.y - src.y * scaleY;applyBoxFit(fit, input, output)根据不同的fit模式计算裁剪源与目标绘制尺寸这对{ src, dst }尺寸该算法的思路与 CSSobject-fit及 Flutter 的BoxFit一致fitRects(fit, rect, { x, y, width, height })将计算出的尺寸通过inscribe分别居中到源矩形与目标矩形中最终得到真正的src/dst矩形若源矩形或目标矩形存在 0 或负的宽高算法会直接返回空的{ src, dst }避免除以零。各fit模式的实际行为可结合fitRects的单元测试FitBox.spec.tsx得到精确结论fill源完全拉伸填满目标宽高比可能被破坏contain保持宽高比完整放入目标内多余空间居中留白例如 2:1 的源放入正方形目标后宽 200、高 100、垂直居中cover保持宽高比并铺满目标超出部分从源中裁剪例如 2:1 源放入正方形目标时源的宽度被裁剪一半并水平居中fitWidth宽度强制匹配目标宽度源高度按比例扩展并可能超出原矩形向上方延伸fitHeight高度强制匹配目标高度宽度按比例调整并居中裁剪none取源与目标各维度较小值不做缩放居中放置scaleDown仅在源大于目标时才等比缩小以适配源比目标小则保持原尺寸不做放大。FitBox.spec.tsx中还有一组直接针对rect2rect的数学断言如非均匀缩放、带偏移的源与目标、负坐标、极小尺寸等见 FitBox.spec.tsx可作为理解矩阵数值行为的参考。此外fitbox()函数还支持可选的rotation: 0 | 90 | 180 | 270参数见 FitBox.tsx会在适配变换之后追加相应的旋转操作方便处理旋转后的适配。小结Group是 React Native Skia 组合能力的核心它把Paint 继承、坐标变换、裁剪与离屏图层统一收口到一个可深度嵌套的组件中配合zIndex控制绘制顺序再由FitBox提供自动缩放适配。实际项目中建议遵循以下实践批量统一样式时把color/style/strokeWidth提到 Group 上利用继承减少重复做整体特效模糊、调色、投影时优先使用layer{Paint…/Paint}效果作用于整组而非单个元素需要围绕任意点变换时用origin属性或Skia.Matrix()/processTransform2d()手动构造矩阵同时避免矩阵内与origin重复施加同一原点需要局部裁剪时clip支持矩形、圆角矩形与任意路径含反转足以覆盖绝大多数遮罩场景需要控制兄弟元素叠放次序时使用zIndex支持负值但注意其作用域仅限父 Group 内部。文中的每个示例都可以在 example 应用与 renderer 测试目录 中找到对应的真实运行与快照验证可以放心地把它们作为你项目中 Group 用法的起点。赞分享图形学移动开发跨平台UI组件【免费下载链接】react-native-skiaHigh-performance React Native Graphics using Skia项目地址https://gitcode.com/gh_mirrors/re/react-native-skia点击查看免费下载相关推荐Mem0 Platform 高级功能实战指南混合检索、实体链接、自定义分类、导出、Webhook 与多模态Mem0 Platform 高级功能实战指南混合检索、实体链接、自定义分类、导出、Webhook 与多模态 本文基于仓库中的 Mem0 Platform 功能图形学移动开发跨平台UI组件React Native Skia遮罩与裁剪终极指南轻松创建惊艳视觉效果React Native Skia遮罩与裁剪终极指南轻松创建惊艳视觉效果 在React Native应用开发中实现复杂的图形效果一直是开发者的挑战。Reac图形学移动开发跨平台UI组件OpCore-Simplify终极指南如何30分钟搞定OpenCore EFI配置成功率92.3%OpCore Simplify终极指南如何30分钟搞定OpenCore EFI配置成功率92.3% 还在为复杂的OpenCore配置而头疼吗OpCore图形学移动开发跨平台UI组件上一篇SVGKit社区贡献指南如何参与开源SVG渲染项目下一篇NextStep-1连续令牌技术引领AI图像生成范式变革创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网