跳到主要内容

Group 组件是 React Native Skia 中的一个基本构造。Group 组件可以彼此深度嵌套。它可以对其子组件应用以下操作

名称类型描述
transform?Transform2d与 React Native 中的 API 相同,但有两个区别:变换的默认原点位于左上角(React Native 视图使用中心),并且所有旋转都以弧度为单位。
origin?Point设置变换的原点。此属性不会被其子元素继承。
clip?RectOrRRectOrPath用于裁剪子元素的矩形、圆角矩形或路径。
invertClip?boolean反转裁剪区域:裁剪区域外的部分将显示,而内部的部分将隐藏。
layer?RefObject<Paint>将子元素绘制为位图,并应用由 paint 提供的效果。

以下三个组件不受组属性的影响。要对这些组件应用绘制效果,您需要使用 图层效果。在每个组件参考中,我们还会记录如何在其上应用绘制效果。

绘制属性

其子元素将继承应用于组的所有绘制属性。这些属性可以是像 colorstyle 这样的属性,也可以是像 <Shader /><ImageFilter /> 这样的子元素(请参阅绘制)。

tsx
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" />
{/* The paint is inherited by the following sibling and descendants. */}
<Group color="lightblue" style="stroke" strokeWidth={10}>
<Circle cx={r} cy={r} r={r / 2} />
<Circle cx={r} cy={r} r={r / 3} color="white" />
</Group>
</Canvas>
);
};
tsx
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" />
{/* The paint is inherited by the following sibling and descendants. */}
<Group color="lightblue" style="stroke" strokeWidth={10}>
<Circle cx={r} cy={r} r={r / 2} />
<Circle cx={r} cy={r} r={r / 3} color="white" />
</Group>
</Canvas>
);
};

Paint Assignment

变换

transform 属性与其在 React Native 中的同名属性 相同,但有一个显著的区别:在 React Native 中,变换的原点是对象的中心,而在 Skia 中,它是对象的左上角位置。

origin 属性是用于设置变换原点的辅助工具。此属性不会被其子元素继承。所有旋转都以弧度为单位。

简单变换

tsx
import { Canvas, Fill, Group, RoundedRect } from "@shopify/react-native-skia";
 
const SimpleTransform = () => {
return (
<Canvas style={{ flex: 1 }}>
<Fill color="#e8f4f8" />
<Group color="lightblue" transform={[{ skewX: Math.PI / 6 }]}>
<RoundedRect x={64} y={64} width={128} height={128} r={10} />
</Group>
</Canvas>
);
};
tsx
import { Canvas, Fill, Group, RoundedRect } from "@shopify/react-native-skia";
 
const SimpleTransform = () => {
return (
<Canvas style={{ flex: 1 }}>
<Fill color="#e8f4f8" />
<Group color="lightblue" transform={[{ skewX: Math.PI / 6 }]}>
<RoundedRect x={64} y={64} width={128} height={128} r={10} />
</Group>
</Canvas>
);
};

Simple Transformation

原点变换

tsx
import { Canvas, Fill, Group, RoundedRect } from "@shopify/react-native-skia";
 
const SimpleTransform = () => {
return (
<Canvas style={{ flex: 1 }}>
<Fill color="#e8f4f8" />
<Group
color="lightblue"
origin={{ x: 128, y: 128 }}
transform={[{ skewX: Math.PI / 6 }]}
>
<RoundedRect x={64} y={64} width={128} height={128} r={10} />
</Group>
</Canvas>
);
};
tsx
import { Canvas, Fill, Group, RoundedRect } from "@shopify/react-native-skia";
 
const SimpleTransform = () => {
return (
<Canvas style={{ flex: 1 }}>
<Fill color="#e8f4f8" />
<Group
color="lightblue"
origin={{ x: 128, y: 128 }}
transform={[{ skewX: Math.PI / 6 }]}
>
<RoundedRect x={64} y={64} width={128} height={128} r={10} />
</Group>
</Canvas>
);
};

Origin Transformation

裁剪操作

clip 提供一个裁剪区域,用于设置应该显示子元素的哪一部分。区域内的部分会显示,而区域外的部分会隐藏。当使用 invertClip 时,裁剪区域外的所有内容都会显示,而裁剪区域内的部分会隐藏。

裁剪矩形

tsx
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 color="lightblue" />
<Group clip={rct}>
<Image
image={image}
x={0}
y={0}
width={size}
height={size}
fit="cover"
/>
</Group>
</Canvas>
);
};
tsx
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 color="lightblue" />
<Group clip={rct}>
<Image
image={image}
x={0}
y={0}
width={size}
height={size}
fit="cover"
/>
</Group>
</Canvas>
);
};

裁剪圆角矩形

tsx
import {
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}
fit="cover"
/>
</Group>
</Canvas>
);
};
tsx
import {
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}
fit="cover"
/>
</Group>
</Canvas>
);
};

裁剪路径

tsx
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} fit="cover" />
</Group>
</Canvas>
);
};
tsx
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} fit="cover" />
</Group>
</Canvas>
);
};

反转裁剪

tsx
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} fit="cover" />
</Group>
</Canvas>
);
};
tsx
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} fit="cover" />
</Group>
</Canvas>
);
};

图层效果

使用 layer 属性将创建一个子元素的位图绘制。您可以使用它来应用效果。这对于构建需要应用于一组元素而不是特定一个元素的效果特别有用。

tsx
import {
Canvas,
Group,
Circle,
Blur,
Paint,
ColorMatrix,
} from "@shopify/react-native-skia";
 
const Clip = () => {
return (
<Canvas style={{ flex: 1 }}>
<Group
color="lightblue"
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>
);
};
tsx
import {
Canvas,
Group,
Circle,
Blur,
Paint,
ColorMatrix,
} from "@shopify/react-native-skia";
 
const Clip = () => {
return (
<Canvas style={{ flex: 1 }}>
<Group
color="lightblue"
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>
);
};
Rasterize

Fitbox

FitBox 组件基于 Group 组件,允许您自动缩放绘图以适应目标矩形。

名称类型描述
srcSKRect缩放前绘图的边界矩形
dstSKRect缩放后绘图的边界矩形
fit?Fit使图像适应矩形的方法。值可以是 containfillcoverfitHeightfitWidthscaleDownnone (默认值为 contain)

示例

考虑以下 SVG 导出。其边界源矩形为 0, 0, 664, 308

xml
<svg width="664" height="308" viewBox="0 0 664 308" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M 170.1 215.5 C 165 222.3..." fill="black"/>
</svg>
xml
<svg width="664" height="308" viewBox="0 0 664 308" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M 170.1 215.5 C 165 222.3..." fill="black"/>
</svg>

我们希望将该路径自动缩放到大小为 256 x 256 的画布上

tsx
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
path="M 170.1 215.5 C 165 222.3..."
strokeCap="round"
strokeJoin="round"
style="stroke"
strokeWidth={30}
/>
</FitBox>
</Canvas>
);
};
tsx
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
path="M 170.1 215.5 C 165 222.3..."
strokeCap="round"
strokeJoin="round"
style="stroke"
strokeWidth={30}
/>
</FitBox>
</Canvas>
);
};