react-native-signature-canvas
基于Canvas的React Native签名组件,适用于Android、iOS和Expo
- 支持Android、iOS和Expo
- 已在RN 0.69上测试
- 核心使用 signature_pad.js
- 生成签名的base64编码png图像 注意:React Native Signature Canvas v1.5.0开始支持Expo SDK v33.0.0及以上版本。
安装(适用于React Native V0.60.0或Expo SDK v35.0.0)
yarn add react-native-signature-canvas
或
npm install --save react-native-signature-canvas
该包依赖于 react-native-webview,特别是在使用React Native CLI时需要。要安装
react-native-webview
,请按照此处提到的步骤操作。
安装(适用于React Native V0.5x.x或Expo SDK < v33)
npm install --save react-native-signature-canvas@1.4.2
使用方法
基本用法
import Signature from "react-native-signature-canvas";
自定义用法
import SignatureScreen from "react-native-signature-canvas";
属性
属性 | 类型 | 描述 |
---|---|---|
androidHardwareAccelerationDisabled | boolean | react-native-webview的androidHardwareAccelerationDisabled选项。默认为false |
autoClear | boolean | 点击确认按钮后是否自动清除签名 |
backgroundColor | string | 默认为"rgba(255,255,255,0)"(透明),画布的背景颜色 |
bgHeight | number | 背景图像的高度 |
bgWidth | number | 背景图像的宽度 |
bgSrc | string | 背景图像源URI(URL) |
clearText | string | 清除按钮文本 |
confirmText | string | 保存按钮文本 |
customHtml | (injectedJavaScript: string) => string | 允许修改布局或元素的HTML字符串 |
dataURL | string | 默认为"",Base64字符串,从dataURL绘制保存的签名 |
descriptionText | string | 签名的描述文本 |
dotSize | number | 单个点的半径(非笔画宽度) |
imageType | string | "image/png"(默认)、"image/jpeg"、"image/svg+xml",导出签名的图像类型 |
minWidth | number | 线条的最小宽度。默认为0.5 |
maxWidth | number | 线条的最大宽度。默认为2.5 |
minDistance | number | 仅当前一个点距离超过x像素时才添加下一个点。默认为5 |
nestedScrollEnabled | boolean | 在scrollview内部使用时启用嵌套滚动 |
showsVerticalScrollIndicator | boolean | 布尔值,决定是否在WebView 中显示垂直滚动指示器。默认值为true |
onOK | function | 保存非空签名后的回调函数 |
onEmpty | function | 尝试保存空签名后的回调函数 |
onClear | function | 清除签名后的回调函数 |
onGetData | function | 调用getData()时的回调函数 |
onBegin | function | 开始新笔画时的回调函数 |
onEnd | function | 笔画结束时的回调函数 |
onLoadEnd | function | webview画布加载结束时的回调函数 |
onUndo | function | 调用undo()时的回调函数 |
onRedo | function | 调用redo()时的回调函数 |
onDraw | function | 启用绘图时的回调函数 |
onErase | function | 启用擦除时的回调函数 |
onChangePenColor | function | 更改笔颜色后的回调函数 |
onChangePenSize | function | 更改笔大小后的回调函数 |
overlayHeight | number | 覆盖图像的高度 |
overlayWidth | number | 覆盖图像的宽度 |
overlaySrc | string | 覆盖图像源URI(URL)必须是具有透明背景的.png文件 |
penColor | string | 默认为"black",笔的颜色 |
rotated | boolean | 将签名板旋转90度 |
style | object | 包装视图的样式 |
trimWhitespace | boolean | 修剪图像白色空间 |
webStyle | string | 用于覆盖默认样式的webview样式,所有样式:https://github.com/YanYuanFE/react-native-signature-canvas/blob/master/h5/css/signature-pad.css |
androidLayerType | none、software、hardware | 设置android webview的layerType |
方法
函数 | 描述 |
---|---|
clearSignature() | 清除当前签名 |
changePenColor(color) | 更改笔颜色 |
changePenSize(minW, maxW) | 更改笔大小 |
draw() | 启用签名绘制 |
erase() | 启用签名擦除 |
getData() | 触发onGetData 回调,传入单个data JSON字符串 |
readSignature() | 读取画布上的当前签名,并触发onOK 或onEmpty 回调 |
undo() | 撤销上一笔 |
redo() | 重做上一笔 |
要调用这些方法,请使用useRef
hook:
import SignatureScreen from "react-native-signature-canvas";
const Sign = ({ text, onOK }) => {
const ref = useRef();
// 在ref.current.readSignature()读取非空base64字符串后调用
const handleOK = (signature) => {
console.log(signature);
onOK(signature); // 来自组件props的回调
};
// 在ref.current.readSignature()读取空字符串后调用
const handleEmpty = () => {
console.log("Empty");
};
// 在ref.current.clearSignature()之后调用
const handleClear = () => {
console.log("clear success!");
};
// 在笔画结束后调用
const handleEnd = () => {
ref.current.readSignature();
};
// 在ref.current.getData()之后调用
const handleData = (data) => {
console.log(data);
};
return (
<SignatureScreen
ref={ref}
onEnd={handleEnd}
onOK={handleOK}
onEmpty={handleEmpty}
onClear={handleClear}
onGetData={handleData}
autoClear={true}
descriptionText={text}
/>
);
};
export default Sign;
使用背景图像
您可以使用bgSrc
属性设置一个不可擦除的背景图像来绘制您的签名。请确保提供图像的宽度和高度。
const imgWidth = 300;
const imgHeight = 200;
const style = `.m-signature-pad {box-shadow: none; border: none; }
.m-signature-pad--body {border: none;}
.m-signature-pad--footer {display: none; margin: 0px;}
body,html {
width: ${imgWidth}px; height: ${imgHeight}px;}`;
...
<View style={{ width: imgWidth, height: imgHeight }}>
<SignatureScreen
ref={ref}
bgSrc="https://via.placeholder.com/300x200/ff726b"
bgWidth={imgWidth}
bgHeight={imgHeight}
webStyle={style}
onOK={handleOK}
/>
</View>
使用覆盖图像
覆盖图是一个不可擦除的图像,可以用作指引,类似于填色书。请确保图像格式为.png,并且具有透明背景。同时,不要忘记提供图像的宽度和高度。
使用overlaySrc
属性提供链接。
const imgWidth = 256;
const imgHeight = 256;
const style = `.m-signature-pad {box-shadow: none; border: none; }
.m-signature-pad--body {border: none;}
.m-signature-pad--footer {display: none; margin: 0px;}
body,html {
width: ${imgWidth}px; height: ${imgHeight}px;}`;
...
<View style={{ width: imgWidth, height: imgHeight }}>
<SignatureScreen
ref={ref}
overlaySrc="http://pngimg.com/uploads/circle/circle_PNG63.png"
overlayWidth={imgWidth}
overlayHeight={imgHeight}
webStyle={style}
onOK={handleOK}
/>
</View>
将Base64图像保存为文件
如果您使用的是expo,可以使用expo-file-system将base64图像保存为本地文件;如果您使用的是react-native-cli,请使用react-native-fs。
import * as FileSystem from "expo-file-system";
const handleOK = (signature) => {
const path = FileSystem.cacheDirectory + "sign.png";
FileSystem.writeAsStringAsync(
path,
signature.replace("data:image/png;base64,", ""),
{ encoding: FileSystem.EncodingType.Base64 }
)
.then(() => FileSystem.getInfoAsync(path))
.then(console.log)
.catch(console.error);
};
基本参数
<Signature
// 点击保存按钮时的处理函数
onOK={(img) => console.log(img)}
onEmpty={() => console.log("empty")}
// 签名的描述文本
descriptionText="Sign"
// 清除按钮文本
clearText="Clear"
// 保存按钮文本
confirmText="Save"
// 字符串,用于覆盖默认样式的webview样式,所有样式:https://github.com/YanYuanFE/react-native-signature-canvas/blob/master/h5/css/signature-pad.css
webStyle={`.m-signature-pad--footer
.button {
background-color: red;
color: #FFF;
}`}
autoClear={true}
imageType={"image/svg+xml"}
/>
如果您创建自己的触发器来读取签名和/或清除签名,可以通过传入webStyle属性的css样式来隐藏内置的清除和保存按钮。
const webStyle = `.m-signature-pad--footer
.save {
display: none;
}
.clear {
display: none;
}
`;
...
<Signature
webStyle={webStyle}
onOK={handleOK}
onEmpty={handleEmpty}
onEnd={handleEnd}
/>
自定义确认和清除按钮
import React, { useRef } from "react";
import { StyleSheet, View, Button } from "react-native";
import SignatureScreen from "react-native-signature-canvas";
const Sign = ({ onOK }) => {
const ref = useRef();
const handleOK = (signature) => {
console.log(signature);
onOK
返回 (
<View style={styles.container}>
<SignatureScreen ref={ref} onOK={handleOK} webStyle={style} />
<View style={styles.row}>
<Button title="清除" onPress={handleClear} />
<Button title="确认" onPress={handleConfirm} />
</View>
</View>
);
export default Sign;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
height: 250,
padding: 10,
},
row: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
alignItems: "center",
},
});
## 示例
- Android <br/>
<img src="http://img.yanyuanfe.cn/signature-android.png" width="400" />
- iOS <br/>
<img src="http://img.yanyuanfe.cn/signature-ios.png" width="400" />
import React, { useState } from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import Signature from "react-native-signature-canvas";
export const SignatureScreen = () => {
const [signature, setSign] = useState(null);
const handleOK = (signature) => {
console.log(signature);
setSign(signature);
};
const handleEmpty = () => {
console.log("空白");
};
const style = `.m-signature-pad--footer
.button {
background-color: red;
color: #FFF;
}`;
return (
<View style={{ flex: 1 }}>
<View style={styles.preview}>
{signature ? (
<Image
resizeMode={"contain"}
style={{ width: 335, height: 114 }}
source={{ uri: signature }}
/>
) : null}
</View>
<Signature
onOK={handleOK}
onEmpty={handleEmpty}
descriptionText="签名"
clearText="清除"
confirmText="保存"
webStyle={style}
/>
</View>
);
};
const styles = StyleSheet.create({
preview: {
width: 335,
height: 114,
backgroundColor: "#F8F8F8",
justifyContent: "center",
alignItems: "center",
marginTop: 15,
},
previewText: {
color: "#FFF",
fontSize: 14,
height: 40,
lineHeight: 40,
paddingLeft: 10,
paddingRight: 10,
backgroundColor: "#69B2FF",
width: 120,
textAlign: "center",
marginTop: 10,
},
});
## 使用 TypeScript
要使用 TypeScript,只需导入 `SignatureViewRef`,并在 [useRef hook](https://reactjs.org/docs/hooks-reference.html#useref) 中指明引用的类型为 `SignatureViewRef`,这样就可以使用常规的 `ref` 方法。
import React, { useRef } from "react";
import SignatureScreen, {
SignatureViewRef,
} from "react-native-signature-canvas";
interface Props {
text: string;
onOK: (signature) => void;
}
const Sign: React.FC<Props> = ({ text, onOK }) => {
const ref = useRef<SignatureViewRef>(null);
const handleSignature = (signature) => {
console.log(signature);
onOK(signature);
};
const handleEmpty = () => {
console.log("空白");
};
const handleClear = () => {
console.log("清除成功!");
};
const handleEnd = () => {
ref.current?.readSignature();
};
return (
<SignatureScreen
ref={ref}
onEnd={handleEnd}
onOK={handleSignature}
onEmpty={handleEmpty}
onClear={handleClear}
autoClear={true}
descriptionText={text}
/>
);
};
export default Sign;
## 在 ScrollView 中使用的示例
当在 ScrollView 中使用 `react-native-signature-canvas` 时,你只能在画布上得到一个点,而 ScrollView 会处理手势,使其无法用于画布。
解决方法是使用 `ScrollView` 的 `scrollEnabled` 属性。
这里有一个示例:
import React, {useState} from 'react';
import {ScrollView, View} from 'react-native';
import Signature from 'react-native-signature-canvas';
const SignInScroll = () => {
const [scrollEnabled, setScrollEnabled] = useState(true);
return (
<ScrollView scrollEnabled={scrollEnabled}>
<View style={{height: 300}}>
<Signature
onOK={(img) => console.log(img)}
onBegin={() => setScrollEnabled(false)}
onEnd={() => setScrollEnabled(true)}
descriptionText="签名"
clearText="清除"
confirmText="保存"
imageType="image/jpeg"
/>
</View>
</ScrollView>
);
};
export default SignInScroll;