鸿蒙Next仿微信朋友圈图片排序删除

2025-06-27 22:47:31
111次阅读
0个评论

上一篇介绍了Grid的图片拖拽排序,这篇加一下拖拽到底部删除图片的功能,仿微信,但是还不是很完美,以后再完善,看一下成果和代码: 演示.gif ###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]);
  }
}

###选取照片组件:

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
    })
  }
}

目前的缺陷: 1.Grid设置拖动时onItemDragStart默认时间是170毫秒,因此不能立马响应,官网给出的解决办法测试了,也不是很完美,需要再研究一下 2.添加图片的icon没有和Grid绑定在一起 3.底部落入区域的图层没有放到图片上层 如果看到的各位大佬有解决办法,欢迎留言,私信,感谢!!!

收藏00

登录 后评论。没有帐号? 注册 一个。