HarmonyOS 鸿蒙Next:如何实现附件视频中效果,在图片列表中长按图片拖拽移动位置改变顺序,且拖拽移动图片时只能和另一张图片对调位置而非插入

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

HarmonyOS 鸿蒙Next:如何实现附件视频中效果,在图片列表中长按图片拖拽移动位置改变顺序,且拖拽移动图片时只能和另一张图片对调位置而非插入 如何实现附件视频中效果
在图片列表中,如何实现长按图片拖拽移动位置改变顺序
在拖拽移动图片只能和另一张图片对调位置,而不是插入到另一张图前

2 回复

可以看下组合手势
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-gestures-pangesture-V5

看下Grid布局的实例2能否满足您的需求
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V13/ts-container-grid-V13

interface IVehicleDoor{
  title:string
  icon:ResourceStr
}
@Entry
@Component
struct IR241010201054128 {
  @State VehicleDoorArr:IVehicleDoor[] = []
  @State CurrentIndex:number = -1
  @State MoveItem:IVehicleDoor = {title:'',icon:''}
  @State ScaleXY:ScaleOptions = {x:1,y:1}
  @State isExtendGridArea:boolean = false
  @State isPress:boolean = false //是否按压
  aboutToAppear(){
    this.getData()
  }
  getData(){
    let list:IVehicleDoor[] = [
      {title:'item1',icon:$r("app.media.startIcon")},
      {title:'item2',icon:$r("app.media.startIcon")},
      {title:'item3',icon:$r("app.media.startIcon")},
      {title:'item4',icon:$r("app.media.startIcon")},
      {title:'item5',icon:$r("app.media.startIcon")},
      {title:'item6',icon:$r("app.media.startIcon")},
      {title:'item7',icon:$r("app.media.startIcon")},
    ]
    if(this.VehicleDoorArr.length==0){
      list.forEach((item:IVehicleDoor,index:number)=>{
        this.VehicleDoorArr.push(item)
      })
    }
  }
  // 交换数组位置
  changeIndex(itemIndex: number, insertIndex: number) {
    const item = this.VehicleDoorArr[itemIndex]
    this.VehicleDoorArr.splice(itemIndex,1)
    this.VehicleDoorArr.splice(insertIndex,0,item )
  }
  //设置拖拽过程中显示的图片。
  @Builder
  pixelMapBuilder(){
    Column(){
      Column(){
        Column(){
          Image(this.MoveItem.icon)
            .width(24)
            .aspectRatio(1)
        }
        .height(56).width(56)
        .borderRadius(56)
        .justifyContent(FlexAlign.Center)
        .backgroundColor(Color.White)
        .draggable(false)//是否支持拖拽
        Text(this.MoveItem.title)
          .height(17)
          .fontSize('12fp')
          .textAlign(TextAlign.Center)
          .fontFamily('PingFang SC')
          .fontWeight(400)
          .margin({top:6})
      }
      .scale(this.ScaleXY)
    }
    .width('25%').height(100)
    .justifyContent(FlexAlign.Center)
  }
  build(){
    Column () {
      Row(){
        Text('拖拽实现自定义排序')
          .width('100%')
          .textAlign(TextAlign.Center)
      }
      .width('100%')
      .height(100)
      Row(){
        Divider()
          .strokeWidth(0.5)
          .width(95)
        Text('长按可拖动顺序')
          .width(112).height(24)
          .fontSize('16fp')
          .fontWeight(400)
          .textAlign(TextAlign.Center)
          .fontFamily('PingFang SC')
          .margin({left:16.5,right:16.5})
        Divider()
          .strokeWidth(0.5)
          .width(95)
      }
      .width('100%')
      .margin({top:24,bottom:24})
      .justifyContent(FlexAlign.Center)
      .alignItems(VerticalAlign.Center)
      Grid(){
        ForEach(this.VehicleDoorArr,(item:IVehicleDoor,index:number)=>{
          GridItem(){
            VehicleDoorItem({VehicleDoorItem:item})
          }
          .scale(this.CurrentIndex === index?this.ScaleXY:{x:1,y:1})
          .onTouch((event: TouchEvent) => {
            // 按下时
            if(event.type === TouchType.Down){
              this.MoveItem = this.VehicleDoorArr[index]
              this.CurrentIndex = index
              this.isPress = true
              setTimeout(()=>{
                if(this.isPress){
                  animateTo({duration:100, curve:Curve.Linear,onFinish:()=>{}},()=>{
                    this.ScaleXY = {x:1.3,y:1.3}
                  })
                }
              },700)
            }
            // 松开时
            if (event.type === TouchType.Up) {
              this.isPress = false
              animateTo({duration:400, curve:Curve.EaseIn,onFinish:()=>{}},()=>{
                this.ScaleXY = {x:1,y:1}
              })
            }
          })
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsGap(31)
      .columnsGap(37)
      .width('100%').layoutWeight(1)
      .padding({left:20,right:20})
      .supportAnimation(true)//开启GridItem支持拖拽动画
      .editMode(true) // 设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem
      .onItemDragMove((event: ItemDragInfo, itemIndex: number, insertIndex: number) => {
        this.ScaleXY = {x:1.3,y:1.3}
      })
      .onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
        // 第一次开始拖拽此事件绑定的组件时,触发回调。
        this.CurrentIndex = itemIndex
        this.MoveItem = this.VehicleDoorArr[itemIndex]
        return this.pixelMapBuilder(); //设置拖拽过程中显示的图片。
      })
      // 停止拖拽行为时,触发回调。
      .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
        // itemIndex拖拽起始位置,insertIndex拖拽插入位置,isSuccess是否成功释放
        if(insertIndex===-1){ //如果insertIndex的值为-1,代表插入位置出现错误
          insertIndex = this.CurrentIndex
        }
        if(insertIndex>this.VehicleDoorArr.length||!isSuccess){
          return
        }
        this.changeIndex(itemIndex,insertIndex)//交换数据位置
        // 停止拖拽时的动画特效
        this.isPress = false
        animateTo({duration:400, curve:Curve.EaseIn,onFinish:()=>{}},()=>{
          this.ScaleXY = {x:1,y:1}
        })
      })
      Blank()
      // 完成按钮
      Row(){
        Button('完成')
          .width(240).height(44)
          .backgroundColor(Color.Transparent)
          .border({width:1})
          .fontColor(Color.Black)
          .padding(0)
          .fontFamily('PingFang SC')
          .fontWeight(400)
          .fontSize('16fp')
          .onClick(()=>{
            // todo:接口提交保存数据
          })
      }
      .margin({bottom:54,top:225})
      .width('100%')
      .justifyContent(FlexAlign.Center)
      .zIndex(99)
    }
    .height('100%').width('100%')
    .backgroundColor('rgba(248, 248, 248, 1)')
    .expandSafeArea([SafeAreaType.SYSTEM,SafeAreaType.KEYBOARD], [ SafeAreaEdge.BOTTOM])
  }
}

@Component
export struct VehicleDoorItem{
  @Prop VehicleDoorItem:IVehicleDoor
  build(){
    Column(){
      Column(){
        Image(this.VehicleDoorItem.icon)
          .width(24)
          .aspectRatio(1)
          .draggable(false)//是否支持拖拽
      }
      .height(56).width(56)
      .borderRadius(56)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(Color.White)
      Text(this.VehicleDoorItem.title)
        .height(17)
        .fontSize('12fp')
        .textAlign(TextAlign.Center)
        .fontFamily('PingFang SC')
        .fontWeight(400)
        .margin({top:6})
    }
  }
}

更多关于HarmonyOS 鸿蒙Next:如何实现附件视频中效果,在图片列表中长按图片拖拽移动位置改变顺序,且拖拽移动图片时只能和另一张图片对调位置而非插入的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,要实现图片列表中长按图片拖拽移动位置并只能和另一张图片对调位置而非插入的功能,可以通过以下步骤实现:

  1. 监听长按事件:为图片列表中的每张图片设置长按事件监听器,当用户长按某张图片时,触发拖拽开始。

  2. 进入拖拽状态:在拖拽开始时,将该图片设置为可拖拽状态,并显示拖拽的视觉效果,如透明度变化或边框高亮。

  3. 监听拖拽移动:在拖拽过程中,持续监听拖拽事件,更新图片的位置,同时确保图片只能在图片列表的范围内移动。

  4. 检测碰撞:当拖拽中的图片与另一张图片碰撞时,触发对调逻辑,即将两张图片的位置互换。

  5. 结束拖拽:当用户释放拖拽时,结束拖拽状态,并更新图片列表的显示顺序。

  6. 限制插入操作:在拖拽逻辑中,确保只有当两张图片碰撞时才进行位置互换,避免拖拽图片插入到其他图片之间。

实现这一功能需要利用HarmonyOS提供的UI框架和事件处理机制。如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部