鸿蒙开发:案例集合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 })
  }
}

🌸🌼🌺

相关推荐
摘星编程11 小时前
OpenHarmony + RN:Bluetooth连接蓝牙外设
react native·react.js·harmonyos
小风呼呼吹儿12 小时前
Flutter 框架跨平台鸿蒙开发 - 车辆保养记录器:智能管理车辆保养全流程
flutter·华为·harmonyos
不会写代码00012 小时前
Flutter 框架跨平台鸿蒙开发 - 在线小说阅读器开发教程
flutter·华为·harmonyos
weixin_5412999414 小时前
鸿蒙应用开发:保存应用数据 - 关系型数据库的使用
数据库·oracle·harmonyos
夜雨声烦丿19 小时前
Flutter 框架跨平台鸿蒙开发 - 万年历应用开发教程
flutter·华为·harmonyos
Swift社区19 小时前
ArkUI 中 Flex 和 Grid 布局的选择与实践
harmonyos·arkui·flex
2501_9444241220 小时前
Flutter for OpenHarmony游戏集合App实战之黑白棋落子翻转
android·开发语言·windows·flutter·游戏·harmonyos
猛扇赵四那边好嘴.21 小时前
Flutter 框架跨平台鸿蒙开发 - 全国公厕查询:智能定位附近公厕
flutter·华为·harmonyos
血色橄榄枝21 小时前
01 Flutter for OpenHarmony
flutter·开源·鸿蒙
2501_9444241221 小时前
Flutter for OpenHarmony游戏集合App实战之消消乐下落填充
android·开发语言·flutter·游戏·harmonyos