功能说明:
- 点击"生成分享二维码"按钮显示弹框
- 弹框中显示生成的二维码
- 点击"保存到相册"将二维码保存到设备相册
- 点击"取消"关闭弹框
一. 生成二维码分享弹框
1. 主界面二维码按钮
具体代码如下:
Column() {
// 主界面按钮
Button('生成分享二维码')
.width(200)
.height(50)
.fontSize(16)
.onClick(() => this.showDialog())
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
2. 显示弹框
// 显示弹框
private async showDialog() {
await this.generateQRCode();
if (this.qrCodeImage) {
this.isDialogShow = true;
}
}
二. 弹框中显示生成的二维码
具体代码如下:
// 二维码弹框
if (this.isDialogShow) {
Stack() {
// 半透明背景
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(0.5)
.onClick(() => this.closeDialog())
// 弹框内容
Column() {
// 标题
Text('分享二维码')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
// 加载状态
if (this.isLoading) {
LoadingProgress()
.width(60)
.height(60)
.margin(20)
} else if (this.qrCodeImage) {
// 二维码图片
Image(this.qrCodeImage)
.width(280)
.height(280)
.margin(10)
.borderRadius(8)
.border({ width: 1, color: '#EEEEEE' })
}
}
.width('80%')
.backgroundColor(Color.White)
.borderRadius(16)
.alignItems(HorizontalAlign.Center)
.shadow({ radius: 24, color: '#000000', offsetX: 0, offsetY: 4 })
}
.width('100%')
.height('100%')
.position({ x: 0, y: 0 })
.zIndex(1)
}
}
三. 将二维码保存到相册
具体代码如下:
// 保存二维码到相册
private async saveToAlbum() {
if (!this.qrCodeImage) return;
const hasPermission = await this.checkPermissions();
if (!hasPermission) {
promptAction.showToast({ message: '需要相册权限才能保存', duration: 2000 });
return;
}
this.saveButtonText = '保存中...';
try {
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
const fileName = `QRCode_${new Date().getTime()}.jpg`;
// 创建图片文件
const photoAsset = await phAccessHelper.createAsset(
photoAccessHelper.PhotoType.IMAGE,
fileName,
{ title: fileName }
);
// 写入文件
const fd = await photoAsset.open('w');
const imagePacker = image.createImagePacker();
const packOpts = { format: 'image/jpeg', quality: 100 };
const arrayBuffer = await imagePacker.packing(this.qrCodeImage, packOpts);
await fs.write(fd, arrayBuffer);
await fs.close(fd);
promptAction.showToast({ message: '二维码已保存到相册', duration: 2000 });
this.closeDialog();
} catch (error) {
console.error('保存失败:', error);
promptAction.showToast({ message: '保存失败,请重试', duration: 2000 });
} finally {
this.saveButtonText = '保存到相册';
}
}
四. 关闭弹框
具体代码如下:
// 操作按钮
Row() {
Button('取消')
.width(120)
.height(40)
.fontColor('#333333')
.backgroundColor('#EEEEEE')
.onClick(() => this.closeDialog())
Button(this.saveButtonText)
.width(120)
.height(40)
.margin({ left: 20 })
.backgroundColor('#0A59F7')
.fontColor(Color.White)
.enabled(!this.isLoading && this.qrCodeImage !== null)
.onClick(() => this.saveToAlbum())
}
.margin({ top: 20, bottom: 20 })
六. 使用说明
1. 1. 此代码需要以下权限,请确保在module.json5中声明:
具体代码如下:
{
"requestPermissions": [
{
"name": "ohos.permission.READ_IMAGEVIDEO",
"reason": "需要读取相册"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"reason": "需要保存图片到相册"
}
]
}
2. 需要安装@ohos/qrcode模块
可以通过以下命令安装:
ohpm install @ohos/qrcode
3. 如果要分享其他数据,只需修改qrCodeData的值即可。
七. 优化
权限管理优化
·添加了动态权限检查
·在保存前确认权限状态
·友好的权限提示
具体代码如下:
// 权限检查
private async checkPermissions(): Promise<boolean> {
try {
const atManager = abilityAccessCtrl.createAtManager();
const permissions: Array<string> = [
'ohos.permission.READ_IMAGEVIDEO',
'ohos.permission.WRITE_IMAGEVIDEO'
];
const result = await atManager.requestPermissionsFromUser(this.context, permissions);
return result.authResults.every(granted => granted);
} catch (error) {
console.error('权限检查失败:', error);
return false;
}
}
完整代码如下:
import { QRCode } from '@ohos/qrcode';
import image from '@ohos.multimedia.image';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
import common from '@ohos.app.ability.common';
import promptAction from '@ohos.promptAction';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
@Entry
@Component
struct QRShareDialog {
@State qrCodeData: string = 'https://example.com'; // 默认二维码数据
@State isDialogShow: boolean = false;
@State qrCodeImage: image.PixelMap | null = null;
@State isLoading: boolean = false;
@State saveButtonText: string = '保存到相册';
private context = getContext(this) as common.UIAbilityContext;
// 权限检查
private async checkPermissions(): Promise<boolean> {
try {
const atManager = abilityAccessCtrl.createAtManager();
const permissions: Array<string> = [
'ohos.permission.READ_IMAGEVIDEO',
'ohos.permission.WRITE_IMAGEVIDEO'
];
const result = await atManager.requestPermissionsFromUser(this.context, permissions);
return result.authResults.every(granted => granted);
} catch (error) {
console.error('权限检查失败:', error);
return false;
}
}
// 优化后的二维码生成
private async generateQRCode() {
this.isLoading = true;
try {
const qrCode = new QRCode();
const options = {
width: 300,
height: 300,
color: '#000000',
background: '#FFFFFF',
margin: 10,
errorCorrectionLevel: 'H'
};
this.qrCodeImage = await qrCode.generate(this.qrCodeData, options);
} catch (error) {
console.error('生成二维码失败:', error);
promptAction.showToast({ message: '生成二维码失败,请重试', duration: 2000 });
} finally {
this.isLoading = false;
}
}
// 显示弹框
private async showDialog() {
await this.generateQRCode();
if (this.qrCodeImage) {
this.isDialogShow = true;
}
}
// 保存二维码到相册
private async saveToAlbum() {
if (!this.qrCodeImage) return;
const hasPermission = await this.checkPermissions();
if (!hasPermission) {
promptAction.showToast({ message: '需要相册权限才能保存', duration: 2000 });
return;
}
this.saveButtonText = '保存中...';
try {
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
const fileName = `QRCode_${new Date().getTime()}.jpg`;
// 创建图片文件
const photoAsset = await phAccessHelper.createAsset(
photoAccessHelper.PhotoType.IMAGE,
fileName,
{ title: fileName }
);
// 写入文件
const fd = await photoAsset.open('w');
const imagePacker = image.createImagePacker();
const packOpts = { format: 'image/jpeg', quality: 100 };
const arrayBuffer = await imagePacker.packing(this.qrCodeImage, packOpts);
await fs.write(fd, arrayBuffer);
await fs.close(fd);
promptAction.showToast({ message: '二维码已保存到相册', duration: 2000 });
this.closeDialog();
} catch (error) {
console.error('保存失败:', error);
promptAction.showToast({ message: '保存失败,请重试', duration: 2000 });
} finally {
this.saveButtonText = '保存到相册';
}
}
build() {
Column() {
// 主界面按钮
Button('生成分享二维码')
.width(200)
.height(50)
.fontSize(16)
.onClick(() => this.showDialog())
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
// 二维码弹框
if (this.isDialogShow) {
Stack() {
// 半透明背景
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(0.5)
.onClick(() => this.closeDialog())
// 弹框内容
Column() {
// 标题
Text('分享二维码')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
// 加载状态
if (this.isLoading) {
LoadingProgress()
.width(60)
.height(60)
.margin(20)
} else if (this.qrCodeImage) {
// 二维码图片
Image(this.qrCodeImage)
.width(280)
.height(280)
.margin(10)
.borderRadius(8)
.border({ width: 1, color: '#EEEEEE' })
}
// 操作按钮
Row() {
Button('取消')
.width(120)
.height(40)
.fontColor('#333333')
.backgroundColor('#EEEEEE')
.onClick(() => this.closeDialog())
Button(this.saveButtonText)
.width(120)
.height(40)
.margin({ left: 20 })
.backgroundColor('#0A59F7')
.fontColor(Color.White)
.enabled(!this.isLoading && this.qrCodeImage !== null)
.onClick(() => this.saveToAlbum())
}
.margin({ top: 20, bottom: 20 })
}
.width('80%')
.backgroundColor(Color.White)
.borderRadius(16)
.alignItems(HorizontalAlign.Center)
.shadow({ radius: 24, color: '#000000', offsetX: 0, offsetY: 4 })
}
.width('100%')
.height('100%')
.position({ x: 0, y: 0 })
.zIndex(1)
}
}
}
八. 使用建议
- 可以根据实际需求调整二维码的大小和边距
- 可以添加输入框让用户自定义二维码内容
- 可以扩展分享功能,除了保存到相册外,还可以添加直接分享到社交平台
- 对于企业应用,可以在二维码中心添加logo