鸿蒙开发:案例集合List:多列表(List)相互拖拽(位置交换)

🎯 案例集合List:多列表(List)相互拖拽(位置交换)

🌍 案例集合List

🚪 最近开启了学员班级点我欢迎加入(学习相关知识可获得定制礼盒)

🏷️ 效果图

待实现(预计这两天)

  • 组件检测左右偏移动效(用于多列表的添加/删除)

已实现

  • 不同列表交换
  • 同列表交换
  • 组件边缘滑动 (原生自带)
  • 拖出/插入过渡动画

📖 参考

🧩 拆解

javascript 复制代码
/**
 * 组件在拖拽中需要用到的额外信息
 */
interface extraParamsObj {
  insertIndex: number // 插入项下标
  selectedIndex: number // 选中项下标
}

/**
 * mockData
 */
class ItemData {
  id: number = 0
  content: string = ''
}

/**
 * 组件标识
 */
enum CompType {
  LeftList = 'LeftList',
  RightList = 'RightList',
}

@Component
export struct MultiListDragAndDrop {
  /**
   * mock数据1
   */
  @State leftList: ItemData[] =
    [
      { id: 1, content: "A" },
      { id: 2, content: "B" },
      { id: 3, content: "C" },
      { id: 4, content: "D" },
      { id: 5, content: "E" },
      { id: 6, content: "F" }
    ]
  /**
   * mock数据2
   */
  @State rightList: ItemData[] =
    [
      { id: 7, content: "G" },
      { id: 8, content: "H" },
      { id: 9, content: "I" },
      { id: 10, content: "j" },
      { id: 11, content: "K" },
      { id: 12, content: "L" },
    ]
  /**
   * 当前拖拽下标
   */
  @State curDragIdx: number = -1
  /**
   * 当前悬停在那个组件上方的下标
   */
  @State hoverIdx: number = -1
  /**
   * 默认组件类型组别
   */
  @State dragType: CompType | undefined = undefined
  /**
   * 当前悬停在那个组件上方
   */
  @State hoverComp: CompType | undefined = undefined

  /**
   * 拖拽项视图
   * @param item
   */
  @Builder
  private dragBuilder(item: ItemData) {
    Text(item.content)
      .width(150)
      .height(50)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .backgroundColor(Color.Orange)
      .textAlign(TextAlign.Center)
      .borderRadius(20)
  }

  /**
   * 拖拽开始统一方法
   * @param compType
   * @param extraParams
   */
  private itemDragAndDropToStart(compType: CompType, extraParams: string) {
    if (this.dragType === undefined) {
      // 保持只要拖拽开始就标记组件唯一标识
      this.dragType = compType
    }
    this.curDragIdx = (JSON.parse(extraParams) as extraParamsObj)?.selectedIndex
  }

  /**
   * 拖拽释放统一方法
   * @param compType
   * @param extraParams
   */
  private itemDragAndDropEnds(compType: CompType, extraParams: string) {
    const insertIdx = (JSON.parse(extraParams) as extraParamsObj)?.insertIndex
    if (insertIdx >= this.listDataType(compType).length) {
      return
    }
    // 交换逻辑
    this.exchangeItem(this.curDragIdx, insertIdx, compType)
    // 重置当前悬停在那个组件上方的下标
    this.hoverIdx = -1
    // 重置组件标识
    this.dragType = this.hoverComp = undefined
  }

  /**
   * 悬停组件过渡
   * @param compType
   * @param extraParams
   */
  private itemDragMove(compType: CompType, extraParams: string) {
    const insertIdx = (JSON.parse(extraParams) as extraParamsObj)?.insertIndex
    if (insertIdx >= this.listDataType(compType).length) {
      return
    }
    this.hoverIdx = insertIdx
    this.hoverComp = compType

    this.getUIContext()
      .getPromptAction()
      .showToast({ message: `当前组件:${compType}---准备替换的目标下标${insertIdx}` })
  }

  /**
   * 交换选项
   * @param curDrag_idx 当前拖拽item下标
   * @param insert_idx 当前插入项下标
   * @param dragType 拖拽组件的类型(标识)
   */
  private exchangeItem(curDrag_idx: number, insert_idx: number, dragType: CompType) {
    /**
     * 判断为同一列表交换
     */
    if (this.dragType === dragType) {
      this.sameListExchange(curDrag_idx, insert_idx, dragType)
      return
    }

    /**
     * 不同列表交换
     */
    switch (this.dragType) {
      case CompType.LeftList:
        this.differentListExchange(this.leftList, this.rightList, curDrag_idx, insert_idx)
        break

      case CompType.RightList:
        this.differentListExchange(this.rightList, this.leftList, curDrag_idx, insert_idx)
        break
    }
  }

  /**
   * 相同列表item交换
   * @param curDrag_idx 当前拖拽item下标
   * @param insert_idx 当前插入项下标
   * @param dragType
   */
  private sameListExchange(curDrag_idx: number, insert_idx: number, dragType: CompType) {
    const exchangeItem: ItemData = this.listDataType(dragType)[curDrag_idx]
    this.listDataType(dragType)[curDrag_idx] = this.listDataType(dragType)[insert_idx]
    this.listDataType(dragType)[insert_idx] = exchangeItem
  }

  /**
   *  不同列表item交换
   * @param list_1
   * @param list_2
   * @param curDrag_idx 当前拖拽item下标
   * @param insert_idx 当前插入项下标
   */
  private differentListExchange(
    list_1: ItemData[],
    list_2: ItemData[],
    curDrag_idx: number,
    insert_idx: number
  ) {
    const exchangeItem: ItemData = list_1[curDrag_idx]
    list_1[curDrag_idx] = list_2[insert_idx]
    list_2[insert_idx] = exchangeItem
  }

  /**
   * 数据类型
   * @param dragType
   * @returns
   */
  private listDataType(dragType: CompType) {
    switch (dragType) {
      case CompType.LeftList:
        return this.leftList

      case CompType.RightList:
        return this.rightList
    }
  }

  build() {
    Row({ space: 10 }) {
      // 左列表
      List({ space: 10 }) {
        ForEach(this.leftList, (item: ItemData, idx: number) => {
          ListItem() {
            ListItemCase({
              item,
              itemIdx: idx,
              hoverIdx: this.hoverIdx,
              defCompType: CompType.LeftList,
              curCompType: this.hoverComp,
            })
          }
          .onDragStart((event: DragEvent, extraParams: string) => {
            this.itemDragAndDropToStart(CompType.LeftList, extraParams)
            return this.dragBuilder(item)
          })
        }, (item: ItemData) => item.id.toString())
      }
      .onDragMove((event: DragEvent, extraParams: string) => {
        this.itemDragMove(CompType.LeftList, extraParams)
      })
      .onDrop((event: DragEvent, extraParams: string) => {
        this.itemDragAndDropEnds(CompType.LeftList, extraParams)
      })
      .width(180)
      .height(230)
      .scrollBar(BarState.On)
      .edgeEffect(EdgeEffect.None)

      // 右列表
      List({ space: 10 }) {
        ForEach(this.rightList, (item: ItemData, idx: number) => {
          ListItem() {
            ListItemCase({
              item,
              itemIdx: idx,
              hoverIdx: this.hoverIdx,
              defCompType: CompType.RightList,
              curCompType: this.hoverComp
            })
          }
          .onDragStart((event: DragEvent, extraParams: string) => {
            this.itemDragAndDropToStart(CompType.RightList, extraParams)
            return this.dragBuilder(item)
          })
        }, (item: ItemData) => item.id.toString())
      }
      .onDragMove((event: DragEvent, extraParams: string) => {
        this.itemDragMove(CompType.RightList, extraParams)
      })
      .onDrop((event: DragEvent, extraParams: string) => {
        this.itemDragAndDropEnds(CompType.RightList, extraParams)
      })
      .width(180)
      .height(230)
      .scrollBar(BarState.On)
      .edgeEffect(EdgeEffect.None)
    }
    .width('100%')
    .height('100%')
    .padding({ left: 10, right: 10 })
    .justifyContent(FlexAlign.Center)
  }
}

@Component
export struct ListItemCase {
  /**
   * 当前项
   */
  @Prop item: ItemData
  /**
   * 当前项下标
   */
  @Prop itemIdx: number
  /**
   * 当前悬停在某个项的下标
   */
  @Prop hoverIdx: number
  /**
   * 默认组件类型
   */
  @Prop defCompType: CompType
  /**
   * 当前组件类型
   */
  @Prop curCompType: CompType

  /**
   *
   * @returns
   */
  private onScale() {
    return this.hoverIdx === this.itemIdx ? 0.75 : 1
  }

  build() {
    Text(this.item.content)
      .width(150)
      .height(50)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .backgroundColor(Color.Orange)
      .textAlign(TextAlign.Center)
      .borderRadius(20)
      .scale(
        this.curCompType === this.defCompType    ?
        { x: this.onScale(), y: this.onScale() } :
        undefined
      )
      .animation({ curve: Curve.Smooth, duration: 200 })
  }
}

🌸🌼🌺

相关推荐
L、2183 小时前
统一日志与埋点系统:在 Flutter + OpenHarmony 混合架构中实现全链路可观测性
javascript·华为·智能手机·electron·harmonyos
hefengbao5 小时前
『京墨文库』鸿蒙版上线!
harmonyos·arkts·arkui·arkdata
赵浩生5 小时前
鸿蒙技术干货6:鸿蒙权限管理与后台任务开发指南(下)
harmonyos
赵浩生5 小时前
鸿蒙技术干货5:鸿蒙权限管理与后台任务开发指南(上)
harmonyos
kirk_wang6 小时前
Flutter插件跨平台适配技术分析之是否需要适配鸿蒙端-screenshot
flutter·华为·harmonyos
kirk_wang6 小时前
Flutter path_provider 在 OpenHarmony 平台上的实现与适配实践
flutter·移动开发·跨平台·arkts·鸿蒙
赵财猫._.7 小时前
React Native鸿蒙开发实战(七):性能优化与调试技巧
react native·性能优化·harmonyos
晚霞的不甘8 小时前
[鸿蒙2025领航者闯关] Flutter + OpenHarmony 模块化架构设计:大型应用的可维护性与协作之道
flutter·华为·harmonyos·鸿蒙·鸿蒙系统
cuicuiniu5219 小时前
释放数字生产力:浩辰CAD看图王适配HarmonyOS 6 系统
华为·harmonyos
晚霞的不甘9 小时前
[鸿蒙2025领航者闯关]:Flutter + OpenHarmony 插件开发指南:打通 Dart 与原生能力的桥梁
flutter·华为·harmonyos