feat: 长按下载图片
This commit is contained in:
parent
106700618d
commit
857a22dd6a
@ -3,8 +3,8 @@ import LogoSvg from "@/assets/icons/svg/logo.svg";
|
||||
import UserinfoTotalSvg from "@/assets/icons/svg/userinfoTotal.svg";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Linking, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import QRDownloadScreen from "./qrCode";
|
||||
|
||||
interface AppDownloadProps {
|
||||
IOS_APP_STORE_URL: string,
|
||||
@ -39,7 +39,8 @@ export const AppDownload = (props: AppDownloadProps) => {
|
||||
<UserinfoTotalSvg style={{ marginBottom: -20, zIndex: 1 }} />
|
||||
<HandlersSvg style={{ marginBottom: -4, zIndex: 3 }} />
|
||||
<View style={styles.qrCode}>
|
||||
<QRCode
|
||||
<QRDownloadScreen url={platform == "ios" ? IOS_APP_STORE_URL : ANDROID_APK_URL} />
|
||||
{/* <QRCode
|
||||
value={platform == "ios" ? IOS_APP_STORE_URL : ANDROID_APK_URL}
|
||||
size={200}
|
||||
color="black"
|
||||
@ -47,7 +48,7 @@ export const AppDownload = (props: AppDownloadProps) => {
|
||||
logoSize={50}
|
||||
logoBorderRadius={10}
|
||||
logoBackgroundColor="#f0f0f0"
|
||||
/>
|
||||
/> */}
|
||||
</View>
|
||||
</View>
|
||||
{/* Description */}
|
||||
|
||||
90
components/download/qrCode.tsx
Normal file
90
components/download/qrCode.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import * as MediaLibrary from 'expo-media-library';
|
||||
import React, { useRef } from 'react';
|
||||
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { captureRef } from 'react-native-view-shot';
|
||||
|
||||
export default function QRDownloadScreen(prop: { url: string }) {
|
||||
const qrViewRef = useRef<View>(null); // 用于截图的引用
|
||||
const [qrValue] = React.useState(prop.url); // 二维码内容
|
||||
|
||||
const saveQRToGallery = async () => {
|
||||
try {
|
||||
// 触发轻震,提升交互感
|
||||
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
|
||||
// 请求相册写入权限
|
||||
const { status } = await MediaLibrary.requestPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
Alert.alert('权限被拒绝', '需要保存图片到相册的权限');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qrViewRef.current) return;
|
||||
|
||||
// 截取二维码视图
|
||||
const uri = await captureRef(qrViewRef, {
|
||||
format: 'png',
|
||||
quality: 1,
|
||||
result: 'tmpfile', // 返回临时文件路径
|
||||
});
|
||||
|
||||
// 保存到相册
|
||||
await MediaLibrary.saveToLibraryAsync(uri);
|
||||
|
||||
Alert.alert('✅ 成功', '二维码已保存到相册!');
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
Alert.alert('❌ 失败', '无法保存图片,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>长按保存二维码</Text>
|
||||
|
||||
{/* 可截图的容器 */}
|
||||
<TouchableOpacity onLongPress={saveQRToGallery} activeOpacity={0.8}>
|
||||
<View ref={qrViewRef} style={styles.qrContainer}>
|
||||
<QRCode value={qrValue} size={200} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.tip}>👉 长按二维码即可保存</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
backgroundColor: '#f8f8f8',
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 20,
|
||||
textAlign: 'center',
|
||||
},
|
||||
qrContainer: {
|
||||
padding: 16,
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
elevation: 3,
|
||||
},
|
||||
tip: {
|
||||
marginTop: 20,
|
||||
color: '#666',
|
||||
fontSize: 14,
|
||||
},
|
||||
});
|
||||
63
package-lock.json
generated
63
package-lock.json
generated
@ -69,6 +69,7 @@
|
||||
"react-native-svg": "^15.11.2",
|
||||
"react-native-toast-message": "^2.3.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-view-shot": "4.0.3",
|
||||
"react-native-web": "~0.20.0",
|
||||
"react-native-webview": "13.13.5",
|
||||
"react-redux": "^9.2.0"
|
||||
@ -6150,6 +6151,15 @@
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@ -7066,6 +7076,15 @@
|
||||
"hyphenate-style-name": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||
@ -10002,6 +10021,19 @@
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
|
||||
@ -15166,6 +15198,19 @@
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-view-shot": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-4.0.3.tgz",
|
||||
"integrity": "sha512-USNjYmED7C0me02c1DxKA0074Hw+y/nxo+xJKlffMvfUWWzL5ELh/TJA/pTnVqFurIrzthZDPtDM7aBFJuhrHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"html2canvas": "^1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-web": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz",
|
||||
@ -17009,6 +17054,15 @@
|
||||
"deprecated": "no longer maintained",
|
||||
"license": "(Unlicense OR Apache-2.0)"
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/thenify": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
@ -17683,6 +17737,15 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
|
||||
|
||||
@ -77,7 +77,8 @@
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-web": "~0.20.0",
|
||||
"react-native-webview": "13.13.5",
|
||||
"react-redux": "^9.2.0"
|
||||
"react-redux": "^9.2.0",
|
||||
"react-native-view-shot": "4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user