跳至主要内容

纹理

在 React Native Skia 中,我们可以使用 Reanimated 直接在 UI 线程上创建纹理。

useTexture

此钩子允许您从 React 元素创建纹理。它接受一个 React 元素和纹理的尺寸作为参数,并返回一个包含纹理的 Reanimated 共享值。

tsx
import { useWindowDimensions } from "react-native";
import { useTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill } from "@shopify/react-native-skia";
import React from "react";
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = useTexture(
<Fill color="cyan" />,
{ width, height }
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}
tsx
import { useWindowDimensions } from "react-native";
import { useTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill } from "@shopify/react-native-skia";
import React from "react";
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = useTexture(
<Fill color="cyan" />,
{ width, height }
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}

useImageAsTexture

此钩子允许您将图像上传到 GPU。它接受图像源作为参数。它会首先从其源加载图像,然后将其上传到 GPU。

tsx
import { useWindowDimensions } from "react-native";
import { useImageAsTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill } from "@shopify/react-native-skia";
import React from "react";
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = useImageAsTexture(
require("./assets/image.png")
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}
tsx
import { useWindowDimensions } from "react-native";
import { useImageAsTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill } from "@shopify/react-native-skia";
import React from "react";
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = useImageAsTexture(
require("./assets/image.png")
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}

usePictureAsTexture

此钩子允许您从 SkPicture 创建纹理。这对于在 React 生命周期之外生成绘图命令或使用命令式 API 构建纹理非常有用。

tsx
import {useWindowDimensions} from "react-native";
import { usePictureAsTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill, Skia } from "@shopify/react-native-skia";
import React from "react";
 
const rec = Skia.PictureRecorder();
const canvas = rec.beginRecording();
canvas.drawColor(Skia.Color("cyan"));
const picture = rec.finishRecordingAsPicture();
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = usePictureAsTexture(
picture,
{ width, height }
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}
tsx
import {useWindowDimensions} from "react-native";
import { usePictureAsTexture } from "@shopify/react-native-skia";
import { Image, Rect, rect, Canvas, Fill, Skia } from "@shopify/react-native-skia";
import React from "react";
 
const rec = Skia.PictureRecorder();
const canvas = rec.beginRecording();
canvas.drawColor(Skia.Color("cyan"));
const picture = rec.finishRecordingAsPicture();
 
const Demo = () => {
const {width, height} = useWindowDimensions();
const texture = usePictureAsTexture(
picture,
{ width, height }
);
return (
<Canvas style={{ flex: 1 }}>
<Image image={texture} rect={{ x: 0, y: 0, width, height }} />
</Canvas>
)
}

底层原理

Reanimated 2 提供了一个 runOnUI 函数,该函数可以在 UI 线程上执行 JavaScript 代码。此函数对于创建可以直接渲染到屏幕画布上的 GPU 纹理特别有用。

tsx
import { useEffect } from "react";
import { runOnUI, useSharedValue } from "react-native-reanimated";
import type { SharedValue } from "react-native-reanimated";
import { Skia, Canvas, Image } from "@shopify/react-native-skia";
import type { SkImage } from "@shopify/react-native-skia";
 
const createTexture = (image: SharedValue<SkImage | null>) => {
"worklet";
const surface = Skia.Surface.MakeOffscreen(200, 200)!;
const canvas = surface.getCanvas();
canvas.drawColor(Skia.Color("cyan"));
surface.flush();
image.value = surface.makeImageSnapshot();
}
 
const Demo = () => {
const image = useSharedValue<SkImage | null>(null);
useEffect(() => {
runOnUI(createTexture)(image);
}, []);
return (
<Canvas style={{ flex: 1 }}>
<Image image={image} x={0} y={0} width={200} height={200} />
</Canvas>
);
};
tsx
import { useEffect } from "react";
import { runOnUI, useSharedValue } from "react-native-reanimated";
import type { SharedValue } from "react-native-reanimated";
import { Skia, Canvas, Image } from "@shopify/react-native-skia";
import type { SkImage } from "@shopify/react-native-skia";
 
const createTexture = (image: SharedValue<SkImage | null>) => {
"worklet";
const surface = Skia.Surface.MakeOffscreen(200, 200)!;
const canvas = surface.getCanvas();
canvas.drawColor(Skia.Color("cyan"));
surface.flush();
image.value = surface.makeImageSnapshot();
}
 
const Demo = () => {
const image = useSharedValue<SkImage | null>(null);
useEffect(() => {
runOnUI(createTexture)(image);
}, []);
return (
<Canvas style={{ flex: 1 }}>
<Image image={image} x={0} y={0} width={200} height={200} />
</Canvas>
);
};

此示例演示如何创建一个纹理,在其上绘制青色,然后使用来自 @shopify/react-native-skiaImage 组件显示它。runOnUI 函数确保纹理创建和绘制操作在 UI 线程上执行,以获得最佳性能。

在运行此代码之前,请确保您已安装必要的软件包并配置您的项目以使用 Reanimated 2 和 @shopify/react-native-skia