HarmonyOS 鸿蒙Next九宫格切图-创意分享新风尚

发布于 1周前 作者 h691938207 来自 鸿蒙OS

HarmonyOS 鸿蒙Next九宫格切图-创意分享新风尚
<markdown _ngcontent-gqq-c237="" class="markdownPreContainer">

作者:狼哥
团队:坚果派
团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙原生应用,三方库60+,欢迎交流。
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

介绍

​ 在社交媒体日益繁荣的今天,九宫格切图以其独特的视觉呈现方式,成为了朋友圈中的一股清新之风。通过将一张完整图片精心切割为九个小方块,再依次排列发布,不仅让图片内容更加层次分明,还能激发观者的探索欲,引导他们逐格浏览,享受发现新细节的乐趣。

​ 九宫格图片的用处广泛而巧妙。它适用于旅行美景的展示,每一格都是一处风景的缩影,串联起一段完整的旅程记忆;也是美食分享的绝佳选择,从食材准备到成品呈现,步步精彩,让人垂涎欲滴;更可用于生活日常的创意记录,无论是温馨的家庭瞬间,还是个人的小确幸,都能在九宫格的框架下,被赋予更多故事性和观赏性。这种创意切图方式,让每一次分享都变得更加有趣和生动,是连接你我,传递美好情感的新桥梁。

效果预览

工程目录

├──entry/src/main/ets                         // 代码区
│  ├──dialog
│  │  └──ImagePicker.ets                      // 图片选择
│  ├──entryability
│  │  └──EntryAbility.ets 
│  ├──model
│  │  ├──ImageModel.ets                       // 图片操作
│  │  └──PictureItem.ets                      // 图片对象
│  └──pages
│     └──Index.ets                            // 首页
└──entry/src/main/resources                   // 应用资源目录
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

具体实现

1. 权限添加

配置文件module.json5里添加读取图片及视频权限和修改图片或视频权限。

"requestPermissions": [
     {
       "name": "ohos.permission.WRITE_MEDIA",
       "usedScene": {
         "abilities": [
           "EntryAbility"
         ],
         "when": "inuse"
       },
       "reason": "$string:WRITE_MEDIA"
     },
     {
       "name": "ohos.permission.MEDIA_LOCATION",
       "usedScene": {
         "abilities": [
           "EntryAbility"
         ],
         "when": "inuse"
       },
       "reason": "$string:MEDIA_LOCATION"
     },
     {
       "name": "ohos.permission.READ_IMAGEVIDEO",
       "usedScene": {
         "abilities": [
           "EntryAbility"
         ],
         "when": "inuse"
       },
       "reason": "$string:READ_IMAGEVIDEO"
     },
     {
       "name": "ohos.permission.WRITE_IMAGEVIDEO",
       "usedScene": {
         "abilities": [
           "EntryAbility"
         ],
         "when": "inuse"
       },
       "reason": "$string:WRITE_IMAGEVIDEO"
     }
   ]
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
2. 图片选择对话

获取本地图片:首先使用getPhotoAccessHelper获取相册管理模块实例,然后使用getAssets方法获取文件资源,最后使用getAllObjects获取检索结果中的所有文件资产方便展示;

let photoList: Array<photoAccessHelper.PhotoAsset> = [];

let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); let fetchOptions: photoAccessHelper.FetchOptions = { fetchColumns: [], predicates: predicates }

let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await this.phAccessHelper.getAssets(fetchOptions); if (fetchResult != undefined) { let photoAsset: Array<photoAccessHelper.PhotoAsset> = await fetchResult.getAllObjects(); if (photoAsset != undefined && photoAsset.length > 0) { for (let i = 0; i < photoAsset.length; i++) { if (photoAsset[i].photoType === 1) { photoList.push(photoAsset[i]); } } } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

自定义对话框显示获取到的本地图片

import { photoAccessHelper } from '@kit.MediaLibraryKit';

@CustomDialog export struct ImagePicker { @Link index: number; private imagesData: Array<photoAccessHelper.PhotoAsset> = []; public controller: CustomDialogController; @State selected: number = 0;

build() { Column() { List({ space: 5 }) { ForEach(this.imagesData, (item: photoAccessHelper.PhotoAsset, index) => { ListItem() { Stack({ alignContent: Alignment.TopEnd }) {…} }, (item: photoAccessHelper.PhotoAsset) => JSON.stringify(item)) } .width(‘95%’) .height(160) .listDirection(Axis.Horizontal)

 </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Row</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> {...}
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">margin</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">({ bottom: </span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">10</span></span></span></span><span class="hljs-function"><span class="hljs-params">, top: </span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">10</span></span></span></span><span class="hljs-function"><span class="hljs-params"> })</span></span></span><span class="hljs-function">

} .width(‘100%’) .padding({ top: 16, left: 16, right: 16 }) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

3. 切图九宫格

使用createImagePacker创建ImagePacker实例,然后使用fs.open打开文件,调用createImageSource接口创建图片源实例方便操作图片,接下来使用getImageInfo方法获取图片大小便于分割,最后使用createPixelMap方法传入每一份的尺寸参数完成图片裁剪。具体就是根据图片选择对话框,选择的下标,到图库里获取到选择的图片,然后以只读方式打开图片,获取打开图片信息,计算出切图后的宽度和高度,根据参数生成新切图,并缓存到数组里,方便显示切图后的九宫格,最后调用存储函数把切图存储到图库里,方便之后使用,比如发朋友图。

async splitPic(index: number): Promise<Array<PictureItem>> {
   // 调用上面函数获取全部图片
   let imagesData: Array<photoAccessHelper.PhotoAsset> = await this.getAllImg();
   console.info(`xx testTag splitPic 图库图片数量为: ${imagesData.length}`)
   let imagePixelMap: Array<PictureItem> = [];
   // 创建图像编码ImagePacker对象
   let imagePickerApi = image.createImagePacker();

// 以只读方式打开指定下标图片 await fileIo.open(imagesData[index].uri, fileIo.OpenMode.READ_ONLY).then(async (file: fileIo.File) => { let fd: number = file.fd; // 获取图片源 let imageSource = image.createImageSource(fd); // 图片信息 let imageInfo = await imageSource.getImageInfo(); // 图片高度除以3,就是把图片切为3份 let height = imageInfo.size.height / this.splitCount; let width = imageInfo.size.width / this.splitCount; // 切换为 3x3 张图片 for (let i = 0; i < this.splitCount; i++) { for (let j = 0; j < this.splitCount; j++) { // 设置解码参数DecodingOptions,解码获取pixelMap图片对象 let decodingOptions: image.DecodingOptions = { desiredRegion: { size: { height: height, // 切开图片高度 width: width // 切开图片宽度 }, x: j * width, // 切开x起始位置 y: i * height // 切开y起始位置 } } // 根据参数重新九宫格图片 let img: image.PixelMap = await imageSource.createPixelMap(decodingOptions); // 把生成新图片放到内存里 imagePixelMap.push(new PictureItem(i * this.splitCount + j, img)); // 保存到相册 await this.savePixelMap(img) } }

 imagePickerApi.release();
 fileIo.closeSync(fd);

})

return imagePixelMap; } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

4. 保存图库

把上面切出来的PixelMap先转为ArrayBuffer,然后通过PhotoAccessHelper模块提供相册管理模块能力,包括创建相册以及访问、修改相册中的媒体数据信息等。把ArrayBuffer保存到图库里。

async savePixelMap(pm: PixelMap) {
   if (this.phAccessHelper === null) {
     return;
   }
   const imagePackerApi: image.ImagePacker = image.createImagePacker();
   const packOpts: image.PackingOption = { format: 'image/jpeg', quality: 30 };
   try {
     const buffer: ArrayBuffer = await imagePackerApi.packing(pm, packOpts);
     let options: photoAccessHelper.CreateOptions = {
       title: new Date().getTime().toString()
     };
 <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> photoUri: <span class="hljs-keyword"><span class="hljs-keyword">string</span></span> = <span class="hljs-keyword"><span class="hljs-keyword">await</span></span> <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, <span class="hljs-string"><span class="hljs-string">'jpg'</span></span>, options);
 <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
 <span class="hljs-keyword"><span class="hljs-keyword">await</span></span> fileIo.write(file.fd, buffer);
 fileIo.closeSync(file);

} catch (err) { console.error(err) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

5. 界面布局

顶部和底部显示红色说明文字,上面默认显示图库第一张图上,点击图片弹出对话框选择图库里的其它图片,下来是个切割九宫格按钮,点击可以把选择的图片切割为九张图片,并自动保存到图库里。

Column() {
     Text(`默认显示图库第一张图片、点击图片弹出图库对话框、选择一张希望切九宫格图片!`)
       .fontSize(10)
       .fontColor(Color.Red)
     Image(this.imgData[this.index]?.uri)
       .objectFit(ImageFit.Contain)
       .width('100%')
       .aspectRatio(1)
       .margin(20)
       .onClick(async () => {
         this.imagePixelMap = [];
         this.imgData = await this.imageModel.getAllImg();
         setTimeout(() => {
           this.dialogController.open();
         }, 200);
       })
 </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Stack</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> {
   </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Divider</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function">
     .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">width</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'100%'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
     .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">color</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(Color.Orange)</span></span></span><span class="hljs-function">
   </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Button</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'切割九宫格'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
     .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">onClick</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(async () =&gt; {
       </span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">this</span></span></span></span><span class="hljs-function"><span class="hljs-params">.imagePixelMap = [];
       </span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">this</span></span></span></span><span class="hljs-function"><span class="hljs-params">.imagePixelMap = await </span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">this</span></span></span></span><span class="hljs-function"><span class="hljs-params">.imageModel.splitPic(</span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">this</span></span></span></span><span class="hljs-function"><span class="hljs-params">.index);
     })</span></span></span><span class="hljs-function">
 }
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">width</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'100%'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">height</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">30</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">

 </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Grid</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span></span><span class="hljs-function"> {
   </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">ForEach</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">this</span></span></span></span><span class="hljs-function"><span class="hljs-params">.imagePixelMap, (item: PictureItem, index:number) =&gt; {
     GridItem() {
       Image(item.pixelMap)
         .width(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'99%'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)
         .objectFit(ImageFit.Fill)
         .height(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">90</span></span></span></span><span class="hljs-function"><span class="hljs-params">)
     }
     .backgroundColor(item.pixelMap === </span></span><span class="hljs-literal"><span class="hljs-function"><span class="hljs-params"><span class="hljs-literal">undefined</span></span></span></span><span class="hljs-function"><span class="hljs-params"> ? </span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'#f5f5f5'</span></span></span></span><span class="hljs-function"><span class="hljs-params"> : </span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'#ffdead'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)
   }, (item: PictureItem) =&gt; JSON.stringify(item))</span></span></span><span class="hljs-function">
 }
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">columnsTemplate</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'1fr 1fr 1fr'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">columnsGap</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">2</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">rowsGap</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">2</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">backgroundColor</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'#fff'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">width</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'100%'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">aspectRatio</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">1</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">margin</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">20</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
 .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">layoutWeight</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">1</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">

 </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Text</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(`</span></span><span class="javascript"><span class="hljs-function"><span class="hljs-params"><span class="javascript">上面九宫格图片已保存到图库、请移步到图库发一个不一样的朋友圈吧!</span></span></span></span><span class="hljs-function"><span class="hljs-params">`)</span></span></span><span class="hljs-function">
   .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">fontSize</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">10</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">
   .</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">fontColor</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(Color.Red)</span></span></span><span class="hljs-function">

} .height(‘100%’) .width(‘100%’) .padding(20) .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Start) <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

6. 权限申请

在页面生命周期aboutToAppear函数时,调用权限申请,并获取图库数据。

const PERMISSIONS: Array<Permissions> = [
 'ohos.permission.READ_MEDIA',
 'ohos.permission.WRITE_MEDIA',
 'ohos.permission.MEDIA_LOCATION',
 'ohos.permission.MANAGE_MISSIONS'
];
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
async aboutToAppear() {
   await abilityAccessCtrl.createAtManager().requestPermissionsFromUser(getContext(this), PERMISSIONS);
   this.imgData = await this.imageModel.getAllImg();
 }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

相关权限

读取图片及视频权限:ohos.permission.READ_IMAGEVIDEO

修改图片或视频权限:ohos.permission.WRITE_IMAGEVIDEO

约束与限制

1.本示例仅支持标准系统上运行,支持设备:华为手机。

2.HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。

3.DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。

4.HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。

</markdown>

关于HarmonyOS 鸿蒙Next九宫格切图-创意分享新风尚的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。
3 回复
狼哥吊炸天
回到顶部