鸿蒙NEXT开发 - 图片选择、沙箱处理与预览教程
·
目录
一、基本介绍
在鸿蒙NEXT应用开发中,图片的选择、处理和预览是常见需求。本教程将重点介绍如何在鸿蒙NEXT应用中实现图片的选择、沙箱处理和预览功能,不涉及后端上传流程。
二、技术要点
本教程涉及的主要技术点包括:
- 使用@kit.CoreFileKit的picker选择用户图片
- 使用fileIo进行文件操作和沙箱处理
- 在鸿蒙应用中预览图片
三、图片选择与沙箱处理
3.1 创建FileUtil工具类
首先创建一个FileUtil.ets文件,用于处理图片选择和沙箱处理:
import { picker } from '@kit.CoreFileKit'
import { fileIo } from '@kit.CoreFileKit'
import { util } from '@kit.ArkTS'
import request from '@ohos.request'
import { promptAction } from '@kit.ArkUI'
class FileUtilModel {
/**
* 选择照片并复制到沙箱
* @param context 上下文
* @returns 返回沙箱内图片路径
*/
selectPhoto(context: Context): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
try {
// 创建图片选择器
const photo = new picker.PhotoViewPicker()
// 调用选择方法
const result = await photo.select({
maxSelectNumber: 1, // 最多选择1张图片
MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE // 仅图片类型
})
if (result.photoUris.length) {
// 获取选择的第一张图片URI
const photoUri = result.photoUris[0]
// 拷贝到沙箱目录
const sandboxPath = await this.copyToSandbox(context, photoUri)
resolve(sandboxPath)
} else {
reject(new Error("未选择图片"))
}
} catch (error) {
reject(new Error(error.message || "选择图片失败"))
}
})
}
/**
* 将图片复制到应用沙箱
* @param context 上下文
* @param sourceUri 源图片URI
* @returns 沙箱内的图片路径
*/
private copyToSandbox(context: Context, sourceUri: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
// 打开源文件
const sourceFile = fileIo.openSync(sourceUri, fileIo.OpenMode.READ_ONLY)
// 生成目标文件名和路径
const defaultDir = context.cacheDir // 使用应用缓存目录
const tempFileName = util.generateRandomUUID() + '.jpg'
const targetPath = defaultDir + '/' + tempFileName
// 复制文件
fileIo.copyFileSync(sourceFile.fd, targetPath)
// 关闭源文件,释放资源
fileIo.closeSync(sourceFile.fd)
// 构建沙箱内URI格式路径
const sandboxUri = `internal://cache/${tempFileName}`
promptAction.showToast({
message: '图片已复制到沙箱',
duration: 2000
})
resolve(sandboxUri)
} catch (error) {
reject(new Error("复制图片到沙箱失败: " + error.message))
}
})
}
/**
* 获取图片的本地路径(用于预览)
* @param uri 沙箱URI
* @returns 可预览的文件路径
*/
getLocalPath(uri: string): string {
if (uri.startsWith('internal://cache/')) {
// 从internal://cache/xxx.jpg 格式转换为 缓存目录路径
const fileName = uri.replace('internal://cache/', '')
return context.cacheDir + '/' + fileName
}
return uri
}
}
// 创建单例
let FileUtil = new FileUtilModel()
export default FileUtil
四、在页面中使用和预览图片
4.1 创建图片选择和预览组件
import FileUtil from '../utils/FileUtil'
import { promptAction } from '@kit.ArkUI'
@Component
export struct ImagePickerComponent {
@State imagePath: string = ''
build() {
Column() {
// 图片预览区域
if (this.imagePath) {
Stack() {
// 显示图片
Image(this.imagePath)
.width('100%')
.height(200)
.objectFit(ImageFit.Cover)
.borderRadius(8)
// 删除按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_delete'))
.width(24)
.height(24)
}
.width(36)
.height(36)
.position({ x: '90%', y: 10 })
.backgroundColor('rgba(0,0,0,0.5)')
.onClick(() => {
this.imagePath = ''
})
}
.width('100%')
.margin({ bottom: 20 })
} else {
// 选择图片按钮
Button('选择图片') {
Image($r('app.media.ic_add_image'))
.width(24)
.height(24)
.margin({ right: 8 })
Text('添加图片')
.fontSize(16)
}
.width('100%')
.height(60)
.margin({ bottom: 20 })
.onClick(() => {
this.selectImage()
})
}
}
.width('100%')
.padding(16)
}
// 选择图片方法
async selectImage() {
try {
// 调用图片选择器
const sandboxUri = await FileUtil.selectPhoto(getContext(this))
// 获取本地路径用于预览
this.imagePath = sandboxUri
promptAction.showToast({
message: '图片选择成功',
duration: 2000
})
} catch (error) {
promptAction.showToast({
message: '选择图片失败:' + error.message,
duration: 2000
})
}
}
}
4.2 在页面中使用该组件
@Entry
@Component
struct ImagePickerPage {
build() {
Column() {
// 顶部标题
Text('图片选择与预览')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 30 })
// 使用图片选择器组件
ImagePickerComponent()
.width('90%')
// 说明文本
Text('选择图片后会自动复制到应用沙箱并预览')
.fontSize(14)
.opacity(0.6)
.margin({ top: 30 })
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Center)
.backgroundColor('#F8F8F8')
}
}
五、沙箱文件操作详解
5.1 沙箱目录说明
鸿蒙NEXT应用中常用的沙箱目录包括:
- context.cacheDir:应用缓存目录,用于存储临时文件,系统可能在空间不足时清理
- context.filesDir:应用文件目录,用于存储应用数据文件
- context.databaseDir:应用数据库目录
5.2 URI格式说明
鸿蒙NEXT中的URI格式主要有:
- internal://cache/xxx.jpg:应用缓存目录下的文件
- internal://app/xxx.jpg:应用目录下的文件
- file:///xxx/xxx.jpg:文件系统路径
在本教程中,我们使用internal://cache/格式来表示沙箱中的图片路径。
六、实际应用示例
6.1 多图片选择与预览
// 多图片选择功能
selectMultiplePhotos(context: Context): Promise<string[]> {
return new Promise<string[]>(async (resolve, reject) => {
try {
// 创建图片选择器
const photo = new picker.PhotoViewPicker()
// 调用选择方法,允许选择多张图片
const result = await photo.select({
maxSelectNumber: 9, // 最多选择9张图片
MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE
})
if (result.photoUris.length) {
// 处理每张图片
const sandboxUris: string[] = []
// 使用Promise.all处理多个异步操作
const copyPromises = result.photoUris.map(uri => this.copyToSandbox(context, uri))
const results = await Promise.all(copyPromises)
promptAction.showToast({
message: `已选择${results.length}张图片`,
duration: 2000
})
resolve(results)
} else {
reject(new Error("未选择图片"))
}
} catch (error) {
reject(new Error(error.message || "选择图片失败"))
}
})
}
6.2 图片网格预览组件
@Component
export struct ImageGridComponent {
@State imageList: string[] = []
build() {
Column() {
// 图片网格显示
if (this.imageList.length > 0) {
Grid() {
ForEach(this.imageList, (image, index) => {
GridItem() {
Stack() {
Image(image)
.width('100%')
.height('100%')
.objectFit(ImageFit.Cover)
.borderRadius(4)
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_delete'))
.width(16)
.height(16)
}
.width(24)
.height(24)
.position({ x: '85%', y: 5 })
.backgroundColor('rgba(0,0,0,0.5)')
.onClick(() => {
this.removeImage(index)
})
}
}
})
// 添加按钮,只在图片数量小于9时显示
if (this.imageList.length < 9) {
GridItem() {
Column() {
Image($r('app.media.ic_add'))
.width(36)
.height(36)
Text('添加')
.fontSize(12)
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.border({ width: 1, style: BorderStyle.Dashed, color: '#CCCCCC' })
.borderRadius(4)
.onClick(() => {
this.selectImages()
})
}
}
}
.columnsTemplate('1fr 1fr 1fr')
.rowsGap(8)
.columnsGap(8)
.width('100%')
} else {
// 未选择图片时显示添加按钮
Button('选择图片') {
Image($r('app.media.ic_add_image'))
.width(24)
.height(24)
.margin({ right: 8 })
Text('添加图片')
.fontSize(16)
}
.width('100%')
.height(60)
.onClick(() => {
this.selectImages()
})
}
}
.width('100%')
}
// 选择多张图片
async selectImages() {
try {
const newImages = await FileUtil.selectMultiplePhotos(getContext(this))
// 合并新选择的图片和已有图片,确保不超过9张
this.imageList = [...this.imageList, ...newImages].slice(0, 9)
} catch (error) {
promptAction.showToast({
message: '选择图片失败:' + error.message,
duration: 2000
})
}
}
// 移除指定索引的图片
removeImage(index: number) {
this.imageList.splice(index, 1)
// 强制更新数组
this.imageList = [...this.imageList]
}
}
七、注意事项与优化建议
7.1 内存管理
- 图片文件操作完成后务必关闭文件描述符,避免内存泄漏
- 不再需要的临时图片文件应该及时删除,避免占用过多存储空间
7.2 图片性能优化
- 可以根据实际需要调整图片尺寸和质量,减小内存占用
- 预览时可以先显示缩略图,提高加载速度
7.3 权限处理
- 使用PhotoViewPicker不需要申请额外权限
- 如果需要保存图片到公共目录,需要申请相应的存储权限
八、总结
本教程详细介绍了鸿蒙NEXT应用中图片的选择、沙箱处理和预览功能的实现方法。通过使用PhotoViewPicker选择图片,将其复制到应用沙箱目录,然后在应用中预览显示。这些基础功能是开发图片相关应用的重要基础,可以根据实际需求进行扩展和优化。
更多推荐


所有评论(0)