开天辟地 HarmonyOS(鸿蒙) - 组件(列表类): List(编辑列表)

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - 组件(列表类): List(编辑列表)

示例如下:

pages\component\list\ListDemo3.ets

/*
 * List - 编辑列表
 */

import { TitleBar } from '../../TitleBar';

@Entry
@Component
struct ListDemo3 {

  build() {
    Column() {
      TitleBar()
      Tabs() {
        TabContent() { MySample1() }.tabBar('多选').align(Alignment.Top)
        TabContent() { MySample2() }.tabBar('自定义拖动排序').align(Alignment.Top)
        TabContent() { MySample3() }.tabBar('横滑,删除,添加').align(Alignment.Top)
      }
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .layoutWeight(1)
    }
  }
}

@Component
struct MySample1 {

  private array: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  @State editFlag: boolean = false
  @State selectedIndexSet: Set<number> = new Set<number>()

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      /*
       * List - 编辑列表
       *   multiSelectable() - 是否支持多选
       *
       * ListItem - list 内的每个 item
       *   selectable() - 是否允许选中
       *   selected() - 是否选中
       *
       * 注:本例用于演示,如何选中 ListItem,以及如何切换到显示多选框的编辑模式
       */
      List({ space: 20 }) {
        ForEach(this.array, (item: number, index: number) => {
          ListItem() {
            Row() {
              Text(item.toString()).height(100)
                .layoutWeight(1)
                .fontSize(48).fontColor(Color.White).textAlign(TextAlign.Center)

              if (this.editFlag) {
                Blank(10)
                Checkbox().width(24).height(24)
                  .select(this.selectedIndexSet.has(index) ? true: false)
                  .onChange((value:boolean) => {
                    if (value) {
                      this.selectedIndexSet.add(index)
                    } else {
                      this.selectedIndexSet.delete(index)
                    }
                  })
              }
            }
          }
          .stateStyles({
            // 普通状态的样式
            normal: {
              .backgroundColor(Color.Orange).borderRadius(20)
            },
            // 手指按下时的样式
            pressed: {
              .backgroundColor(Color.Blue).borderRadius(5)
            },
            // 选中时的样式
            selected: {
              .backgroundColor(Color.Green).borderRadius(5)
            },
          })
          .selectable(true)
          .selected(this.selectedIndexSet.has(index) ? true: false)
        })
      }
      .width('100%')
      .height('100%')
      .multiSelectable(true)

      Button('切换编辑模式')
        .onClick(() => {
          this.editFlag = !this.editFlag
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Yellow)
  }
}

@Component
struct MySample2 {

  @State private array: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

  @State dragItem: string | undefined = undefined // 拖动中的 item 的内容
  @State offsetY: number = 0 // 拖动中的 item 的位移距离
  @State prevOffsetY: number = 0

  private itemHeight: number = 120 // 每个 item 的高度

  // 指定的 item 的缩放倍数
  itemScale(item: string): number {
    if (this.dragItem == undefined) {
      return 1
    }

    if (this.dragItem == item) {
      return 1.1
    } else {
      return 0.9
    }
  }

  // 排序数据(this.array 是 @State 装饰的,更新后会刷新绑定的组件)
  moveData(index: number, newIndex: number): void {
    let tmp = this.array.splice(index, 1)
    this.array.splice(newIndex, 0, tmp[0])
  }

  build() {
    Stack() {
      /*
       * List - 编辑列表
       * 本例用于演示,如何通过自定义的方式实现 ListItem 的拖动排序
       * 另外,通过 ForEach 可以更方便地实现 ListItem 的拖动排序,详见 /component/list/ListDemo5.ets 中的说明
       */
      List({ space: 20, initialIndex: 0 }) {
        ForEach(this.array, (item: string) => {
          ListItem() {
            Text(item.toString()).height(100).width('100%')
              .fontSize(48).fontColor(Color.White).textAlign(TextAlign.Center)
              .backgroundColor(Color.Orange).borderRadius(20)
          }
          .margin({ left: 20, right: 20 })
          .zIndex(this.dragItem == item ? 1 : 0)
          .scale({ x: this.itemScale(item), y: this.itemScale(item) })
          .translate(this.dragItem == item ? { y: this.offsetY } : { y: 0 })
          .gesture(
            GestureGroup(GestureMode.Sequence,
              LongPressGesture({ repeat: true })
                .onAction((event: GestureEvent) => {
                  animateTo({ curve: Curve.Ease, duration: 500 }, () => {
                    this.dragItem = item
                  })
                })
                .onActionEnd(() => {
                  animateTo({ curve: Curve.Ease, duration: 500 }, () => {
                    this.dragItem = undefined
                  })
                }),
              PanGesture({ fingers: 1 })
                .onActionStart(() => {
                  this.dragItem = item
                  this.prevOffsetY = 0
                })
                .onActionUpdate((event: GestureEvent) => {
                  let index = this.array.indexOf(item)

                  // 计算拖动中的 ListItem 的位移距离
                  this.offsetY = event.offsetY - this.prevOffsetY

                  // 根据用户的操作排序数据
                  if (this.offsetY > this.itemHeight / 2) {
                    animateTo({ curve: Curve.Ease }, () => {
                      this.offsetY -= this.itemHeight
                      this.prevOffsetY += this.itemHeight
                      // 排序数据(this.array 是 @State 装饰的,更新后会刷新绑定的组件)
                      this.moveData(index, index + 1)
                    })
                  } else if (this.offsetY < -this.itemHeight / 2) {
                    animateTo({ curve: Curve.Ease }, () => {
                      this.offsetY += this.itemHeight
                      this.prevOffsetY -= this.itemHeight
                      // 排序数据(this.array 是 @State 装饰的,更新后会刷新绑定的组件)
                      this.moveData(index, index - 1)
                    })
                  }
                })
                .onActionEnd((event: GestureEvent) => {
                  animateTo({ curve: Curve.Ease, duration: 500 }, () => {
                    this.dragItem = undefined
                    this.offsetY = 0
                  })
                }))
              .onCancel(() => {
                animateTo({ curve: Curve.Ease, duration: 500 }, () => {
                  this.dragItem = undefined
                  this.offsetY = 0
                })
              })
          )
        })
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Yellow)
  }
}

@Component
struct MySample3 {

  @State message: string = ""
  @State message2: string = ""
  @State array: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  private listScroller: ListScroller = new ListScroller()

  // 横滑后 item 左侧的组件
  @Builder itemStart() {
    Checkbox().width(24).height(24).margin(10)
  }

  // 横滑后 item 右侧的组件
  @Builder itemEnd(item: number) {
    Row() {
      Button("删除").margin(2).onClick(() => {
        let index = this.array.indexOf(item)
        this.array.splice(index, 1)
      })
      Button("取消").margin(2).onClick(() => {
        // 关闭所有 item 的横滑状态
        this.listScroller.closeAllSwipeActions()
      })
    }
    .padding(10)
    .justifyContent(FlexAlign.SpaceEvenly)
  }

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      /*
       * List - 编辑列表
       * 本例用于演示,横滑显示 item 的操作按钮,左滑删除 item,添加新的 item
       *
       * ListItem - list 内的每个 item
       *   swipeAction() - 横滑操作
       *     start, end - 横滑后 item 左侧的组件和右侧的组件(可以指定一个自定义组件,或者一个 SwipeActionItem 对象)
       *       builder - 需要显示的自定义组件
       *       actionAreaDistance - 左滑时,完整显示了 end 组件后,再至少滑动 actionAreaDistance(默认值为 56)指定的距离且抬起手指后,则触发 onAction 回调
       *       onAction - 左滑删除手势完成后的回调
       *       onEnterActionArea - 横滑时,进入左滑删除区域时的回调
       *       onExitActionArea - 横滑时,离开左滑删除区域时的回调
       *       onStateChange - 横滑后,且抬起手指后,当前状态发生变化后的回调(SwipeActionState 枚举)
       *         COLLAPSED - 当前 item 处于普通状态
       *         EXPANDED - 当前 item 处于显示了左侧组件或右侧组件的状态
       *         ACTIONING - 当前 item 处于触发了左滑删除手势的状态
       *     edgeEffect - 横滑后的回弹效果(SwipeEdgeEffect.None 或 SwipeEdgeEffect.Spring)
       *     onOffsetChange - 横滑时 item 的偏移量发生变化时的回调
       *       offset - 当前 item 的偏移量
       * ListScroller - 用于和绑定的 List 之间的交互(继承自 Scroller)
       */
      List({ space: 20, scroller: this.listScroller }) {
        ForEach(this.array, (item: number) => {
          ListItem() {
            Text(item.toString()).height(100).width('100%')
              .fontSize(48).fontColor(Color.White).textAlign(TextAlign.Center)
              .backgroundColor(Color.Orange).borderRadius(20)
          }
          .margin({ left: 20, right: 20 })
          // ListItem 添加和删除时的动画效果
          .transition(
              TransitionEffect.OPACITY.animation({ duration: 1000 })
          )
          .swipeAction({
            end: {
              builder: () => { this.itemEnd(item) },
              actionAreaDistance: 56,
              onAction: () => {
                // 删除当前 item
                let index = this.array.indexOf(item)
                this.array.splice(index, 1)
              },
              onEnterActionArea: () => {
                this.message = 'onEnterActionArea'
              },
              onExitActionArea: () => {
                this.message = 'onExitActionArea'
              },
              onStateChange: (state:SwipeActionState) => {
                this.message = `state:${SwipeActionState[state]}`
              },
            },
            start: this.itemStart,
            edgeEffect: SwipeEdgeEffect.Spring,
            onOffsetChange: (offset: number) => {
              this.message2 = `onOffsetChange:${offset}`
            }
          })
        })
      }
      Column({space:10}) {
        Button('在位置 0 处添加一项')
          .onClick(() => {
            this.array.unshift(Math.floor(Math.random() * 1000))
          })

        Text(this.message).fontSize(16).fontColor(Color.White).backgroundColor(Color.Blue)
        Text(this.message2).fontSize(16).fontColor(Color.White).backgroundColor(Color.Blue)
      }
      .hitTestBehavior(HitTestMode.None)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Yellow)
  }
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-02-06 08:41  webabcd  阅读(132)  评论(0)    收藏  举报