鸿蒙 Next 仿微信朋友圈图片排序删除
作者:auhgnixgnahz
- 2025-06-23 北京
本文字数:5844 字
阅读完需:约 19 分钟
上一篇介绍了 Grid 的图片拖拽排序,这篇加一下拖拽到底部删除图片的功能,仿微信,但是还不是很完美,以后再完善,看一下成果和代码:

Page 代码:
import { CustomContentDialog, display } from "@kit.ArkUI"
import Logger from "../utils/Logger";
let displayWidthVp = px2vp(display.getDefaultDisplaySync().width);
let displayHeightVp = px2vp(display.getDefaultDisplaySync().height);
@Builder
export function PublishViewBuilder() {
PublishView()
}
@Entry
@ComponentV2
struct PublishView {
@Local inputContent: string = ''
@Local htmlste: string = ''
@Local imgs: string[] = []
@Local showDeleteImg:boolean =false
pathStack: NavPathStack = new NavPathStack()
inputstr:string=''
selectImgWigth :number = Math.ceil((displayWidthVp-20)/3);
contentHeight:number=0;
@Builder
buildContent(): void {
Column() {
TextInput({placeholder:'输入地址'}).onChange((e)=>{
this.inputstr=e
})
}.padding({left:10,right:10})
.width('100%')
}
dialogController: CustomDialogController = new CustomDialogController({
builder: CustomContentDialog({
primaryTitle: '标题',
secondaryTitle: '辅助文本',
contentBuilder: () => {
this.buildContent();
},
buttons: [
{
value: '取消',
buttonStyle: ButtonStyleMode.TEXTUAL,
action: () => {
this.inputstr=''
this.dialogController.close()
}
},
{
value: '确定',
buttonStyle: ButtonStyleMode.TEXTUAL,
action: () => {
this.htmlste=this.inputstr
this.dialogController.close()
}
}
],
}),
});
//拖拽过程样式
@Builder pixelMapBuilder(imgSource:string) {
Image(imgSource).objectFit(ImageFit.Cover).width(this.selectImgWigth).height(this.selectImgWigth)
.draggable(false)
}
@Builder
gridItem(item:number){
Image(item).objectFit(ImageFit.Cover).width('90%').height('90%')
.draggable(false)
}
build() {
NavDestination() {
Column({ space: 5 }) {
Row() {
Image($r('app.media.ic_about_return')).width(20).height(20).objectFit(ImageFit.Contain)
.onClick(() => {
this.pathStack.pop()
})
Text('发表动态').fontSize(20)
Text('发送').fontSize(20)
}
.alignItems(VerticalAlign.Bottom)
.backgroundColor(Color.White)
.height('10%')
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding({ left: 10, right: 10, bottom: 20 })
TextArea({ placeholder: '欢迎关注HarmonyOS开发者笔记共同学习进步' }).width('100%')//去除默认圆角矩形背景
.backgroundColor(Color.Transparent)
.padding(10)
.onChange((value: string) => {
this.inputContent = value
})
Text(this.htmlste)
.width('100%')
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
.fontColor(Color.Blue)
.fontSize(20)
.backgroundColor(Color.Gray)
Stack(){
}
Grid() {
ForEach(this.imgs, (item: string,index:number) => {
GridItem() {
Image(item).objectFit(ImageFit.Cover).width(this.selectImgWigth*0.9).height(this.selectImgWigth*0.9)
.draggable(false)
}
}, (item: string) => item)
}
.width('100%')
.height(Math.ceil(this.imgs.length/3)*this.selectImgWigth)
.columnsTemplate('1fr 1fr 1fr')
// .maxCount(9)
// .layoutDirection(GridDirection.Row)
// .columnsGap(10)
.rowsGap(10)
.padding({ left: 10, right: 10 })
.editMode(true)
.supportAnimation(true)
//第一次拖拽此事件绑定的组件时,触发回调。
.onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
Logger.info('========onItemDragStart','x: '+event.x+'y: '+event.y+'itemIndex:'+itemIndex)
//设置拖拽过程中显示的图片。
return this.pixelMapBuilder(this.imgs[itemIndex]);
})
.onItemDragMove((event: ItemDragInfo, itemIndex: number, insertIndex: number) => {
this.showDeleteImg = false
Logger.info('========onItemDragMove','x: '+event.x+'y: '+event.y+'屏幕高:'+displayHeightVp)
})
.onItemDragLeave((event: ItemDragInfo, itemIndex: number)=>{
this.showDeleteImg = true
Logger.info('========onItemDragLeave','x: '+event.x+'y: '+event.y)
})
//当在本组件范围内停止拖拽行为时,触发回调。
.onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number,
isSuccess: boolean) => {
Logger.info('========onItemDrop','x: '+event.x+'y: '+event.y+'itemIndex:'+itemIndex)
if (event.y>(this.contentHeight-40)){
this.imgs.splice(itemIndex,1)
this.showDeleteImg = false
return
}
if (!isSuccess || insertIndex >= this.imgs.length) {
return;
}
this.changeIndex(itemIndex, insertIndex);
})
Image($r('app.media.icon_add_pic')).width(this.selectImgWigth*0.9).height(this.selectImgWigth*0.9).onClick(() => {
this.pathStack.pushPath({
name: 'photoPicker', onPop: (popInfo: PopInfo) => {
let selectUris: Array<string> = popInfo.result as Array<string>
if (null != selectUris.length) {
this.imgs = []
for (let str of selectUris) {
this.imgs.push(str)
}
}
}
})
}).visibility(this.imgs.length>8?Visibility.None:Visibility.Visible)
.draggable(false).margin({left:10})
Divider().width('100%').height(1).color('#ffe9f0f0')
Column(){
Row(){
Text('拖到此处即可删除').fontColor(Color.White)
}.backgroundColor(Color.Red).width('100%').height(40).justifyContent(FlexAlign.Center)
.visibility(this.showDeleteImg?Visibility.Visible:Visibility.None)
}.width('100%').layoutWeight(1).justifyContent(FlexAlign.End)
}.width('100%').height('100%')
.alignItems(HorizontalAlign.Start)
.onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) =>{
this.contentHeight = newValue.height as number
})
}.backgroundColor(Color.White).hideTitleBar(true).hideToolBar(true)
.onReady((context: NavDestinationContext) => {
this.pathStack = context.pathStack
})
}
//拖拽之后改变元素位置
changeIndex(index1: number, index2: number) {
//这种方式可以保存移动过程中的其他元素位置变化
let tmp = this.imgs.splice(index1, 1);
this.imgs.splice(index2, 0, tmp[0]);
}
}
</string></string>
复制代码
选取照片组件:
import {
PhotoPickerComponent,
PickerController,
PickerOptions,
BaseItemInfo,
ItemInfo,
PhotoBrowserInfo,
ItemType,
ClickType,
MaxCountType,
ReminderMode,
} from '@ohos.file.PhotoPickerComponent';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
@Builder
export function PhotoPickerBuilder() {
PhotoPicker()
}
@ComponentV2
struct PhotoPicker{
pathStack: NavPathStack = new NavPathStack()
// 组件初始化时设置参数信息
pickerOptions: PickerOptions = new PickerOptions();
// 已选择的图片
@Local selectUris: Array<string> = new Array<string>();
//目前选择的图片
@Local currentUri: string = '';
//是否显示大图
@Local isBrowserShow: boolean = false;
aboutToAppear() {
// 设置picker宫格页数据类型
this.pickerOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE // 图片和照片都显示;
// 最大选择数量
this.pickerOptions.maxSelectNumber = 6;
// 超出最大选择数量时
this.pickerOptions.maxSelectedReminderMode = ReminderMode.TOAST;
// 是否展示搜索框,默认false
this.pickerOptions.isSearchSupported = false;
// 是否支持拍照,默认false
this.pickerOptions.isPhotoTakingSupported = true;
}
// 资源被选中回调,返回资源的信息,以及选中方式
private onItemClicked(itemInfo: ItemInfo, clickType: ClickType): boolean {
if (!itemInfo) {
return false;
}
let type: ItemType | undefined = itemInfo.itemType;
let uri: string | undefined = itemInfo.uri;
if (type === ItemType.CAMERA) {
// 点击相机item
return true; // 返回true则拉起系统相机,若应用需要自行处理则返回false。
} else {
if (clickType === ClickType.SELECTED) {
// 应用做自己的业务处理
if (uri) {
this.selectUris.push(uri);
this.pickerOptions.preselectedUris = [...this.selectUris];
}
return true; // 返回true则勾选,否则则不响应勾选。
} else {
if (uri) {
this.selectUris = this.selectUris.filter((item: string) => {
return item != uri;
});
this.pickerOptions.preselectedUris = [...this.selectUris];
}
}
return true;
}
}
// 进入大图的回调
private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
this.isBrowserShow = true;
return true;
}
// 退出大图的回调
private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean {
this.isBrowserShow = false;
return true;
}
// 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。
private onPickerControllerReady(): void {
}
// 大图左右滑动的回调
private onPhotoBrowserChanged(browserItemInfo: BaseItemInfo): boolean {
this.currentUri = browserItemInfo.uri ?? '';
return true;
}
// 已勾选图片被删除时的回调
private onSelectedItemsDeleted(baseItemInfos: Array<baseiteminfo>): void {
}
// 超过最大选择数量再次点击时的回调
private onExceedMaxSelected(exceedMaxCountType: MaxCountType): void {
}
// 当前相册被删除时的回调
private onCurrentAlbumDeleted(): void {
}
build() {
NavDestination(){
Column(){
Row(){
Button('返回').onClick(()=>{
this.pathStack.pop()
})
Button('确定').onClick(()=>{
this.pathStack.pop(this.selectUris)
})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
PhotoPickerComponent({
pickerOptions: this.pickerOptions,
onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean => this.onItemClicked(itemInfo, clickType),
onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onEnterPhotoBrowser(photoBrowserInfo),
onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onExitPhotoBrowser(photoBrowserInfo),
onPickerControllerReady: (): void => this.onPickerControllerReady(),
onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean => this.onPhotoBrowserChanged(browserItemInfo),
onSelectedItemsDeleted: (BaseItemInfo: Array<baseiteminfo>) => this.onSelectedItemsDeleted(BaseItemInfo),
onExceedMaxSelected: (exceedMaxCountType: MaxCountType) => this.onExceedMaxSelected(exceedMaxCountType),
onCurrentAlbumDeleted: () => this.onCurrentAlbumDeleted(),
pickerController: new PickerController(),
})
}
}.backgroundColor(Color.White).hideTitleBar(true).hideToolBar(true)
.onReady((context: NavDestinationContext) => {
this.pathStack = context.pathStack
})
}
}
</baseiteminfo></baseiteminfo></string></string>
复制代码
目前的缺陷:
1.Grid 设置拖动时 onItemDragStart 默认时间是 170 毫秒,因此不能立马响应,官网给出的解决办法测试了,也不是很完美,需要再研究一下
2.添加图片的 icon 没有和 Grid 绑定在一起
3.底部落入区域的图层没有放到图片上层
如果看到的各位大佬有解决办法,欢迎留言,私信,感谢!!!
划线
评论
复制
发布于: 刚刚阅读数: 2
版权声明: 本文为 InfoQ 作者【auhgnixgnahz】的原创文章。
原文链接:【http://xie.infoq.cn/article/23ac2dcb33e853d0a5e348403】。文章转载请联系作者。

auhgnixgnahz
关注
还未添加个人签名 2018-07-10 加入
还未添加个人简介
评论