HarmonyOS 鸿蒙Next 使用List和ListItemGroup删除分组里的一个item

HarmonyOS 鸿蒙Next 使用List和ListItemGroup删除分组里的一个item

@State观察不到数组内元素类的变量改变,我的代码:

cke_2303.png

const alphabets = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

class ContactGroup {
  title: string
  contactGroup: MyContact[]

  constructor(title: string, contactGroup: MyContact[]) {
    this.title = title
    this.contactGroup = contactGroup
  }
}

class MyContact {
  name: string
  headPic: Resource

  constructor(name: string, headPic: Resource) {
    this.name = name
    this.headPic = headPic
  }
}

@Component
struct ContactListPage {
  [@State](/user/State) message: string = 'Hello World'
  [@State](/user/State) contactList: ContactGroup[] = []
  private scroller: Scroller = new Scroller()
  [@State](/user/State) scrollIndex: number = 0

  aboutToAppear() {
    alphabets.forEach((item, index) => {
      if (index > 0) {
        let contactGroup = new ContactGroup();
        contactGroup.title = item
        contactGroup.contactGroup = [
          new MyContact(`${item}1`, $r('app.media.icon')),
          new MyContact(`${item}2`, $r('app.media.icon'))
        ]
        this.contactList[index - 1] = contactGroup
      }
    })
  }

  build() {
    Stack() {
      List({ space: 10, scroller: this.scroller }) {
        ForEach(this.contactList, (contactGroup: ContactGroup, index) => {
          ListItemGroup({ space: 10, header: this.getGroupHeader(contactGroup.title) }) {
            ForEach(contactGroup.contactGroup, (contact: MyContact, itemIndex) => {
              ListItem() {
                Row() {
                  Image(contact.headPic).width(50).height(50).margin({ top: 10, left: 20 })
                  Text(contact.name).fontSize(18).padding(5)
                }.width('100%')
              }.swipeAction({ end: this.itemEnd(index, itemIndex) })

            })
          }.padding({ left: 10 })
        })
      }.sticky(StickyStyle.Header)
      .width('100%')
      .height('100%')
      .onScrollIndex((startIndex) => {
        this.scrollIndex = startIndex
      })

      AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
        .selected(this.scrollIndex + 1)
        .itemSize(20)
        .margin({ right: 20 })
        .onSelect((index) => {
          this.scroller.scrollToIndex(index)
        })
    }.alignContent(Alignment.End)
  }

  @Builder itemEnd(groupIndex: number, itemIndex: number) {
    Button({ type: ButtonType.Normal }) {
      Text('Delete').padding(10).fontColor(Color.White)
    }
    .backgroundColor(Color.Red)
    .height(50)
    .onClick(() => {
      console.log(`${groupIndex}:${itemIndex}index`)
      this.contactList[groupIndex].contactGroup.splice(itemIndex, 1)//在这里移除分组item,UI不会刷新,只能观察到contactList的变化
    })
  }

  @Builder getGroupHeader(title: string) {
    Text(title)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }
}

更多关于HarmonyOS 鸿蒙Next 使用List和ListItemGroup删除分组里的一个item的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

我去,我也写了同样一个demo,也遇到了同样的问题,请问解决了嘛?就是这种复杂的数据对象面对listgroup的时候很无助啊!

更多关于HarmonyOS 鸿蒙Next 使用List和ListItemGroup删除分组里的一个item的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


一直忙,鸿蒙学习中断了。不知道你解决没有,我说一下我后来的解决方式。

定义一个整型State 标记flag,删除操作修改数据源的同时flag++,ListGroup渲染外层加上flag判断,flag发生改变重新渲染数据,

数据源被@State装饰器修饰,ArkUI框架能够感知到数据源长度的变化,并触发ForEach进行重新渲染。但是当数据源的数组项为对象数据类型,并且只修改某个数组项的属性值时,由于数据源为复杂数据类型,ArkUI框架无法监听到@State装饰器修饰的数据源数组项的属性变化,从而无法触发ForEach的重新渲染。为实现ForEach重新渲染,需要结合@Observed和@ObjectLink装饰器使用。参考:@。最后,比较推荐使用LazyForEach来做渲染,性能比较好。

我本来是使用了 @Observed[@ObjectLink](/user/ObjectLink) 的,下面是代码,编译报错:The regular property ‘groupInfo’ cannot be assigned to the @ObjectLink property ‘group’,这是为什么啊

const alphabets = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

@Observed
class ContactGroup {
  title: string
  contactGroup: MyContact[]
}

class MyContact {
  name: string
  headPic: Resource

  constructor(name: string, headPic: Resource) {
    this.name = name
    this.headPic = headPic
  }
}

@Entry
@Component
struct ContactListPage {
  @State message: string = 'Hello World'
  @State contactList: ContactGroup[] = []
  private scroller: Scroller = new Scroller()
  @State scrollIndex: number = 0

  aboutToAppear() {
    alphabets.forEach((item, index) => {
      if (index > 0) {
        let contactGroup = new ContactGroup();
        contactGroup.title = item
        contactGroup.contactGroup = [
          new MyContact(`${item}1`, $r('app.media.icon')),
          new MyContact(`${item}2`, $r('app.media.icon'))
        ]
        this.contactList[index -1] = contactGroup
      }
    })
  }

  build() {
    Stack() {
      List({ space: 10, scroller: this.scroller }) {
        ForEach(this.contactList, (groupInfo: ContactGroup, index) => {
          ListItemGroup({ space: 10, header: this.getGroupHeader(groupInfo.title) }) {
            ForEach(groupInfo.contactGroup, (contact: MyContact, itemIndex) => {
              ListItem() {
                ContactItem({group: groupInfo, index: itemIndex})
                // Row() {
                //   Image(contact.headPic).width(50).height(50).margin({ top: 10, left: 20 })
                //   Text(contact.name).fontSize(18).padding(5)
                // }.width('100%')
              }.swipeAction({ end: this.itemEnd(index, itemIndex) })
            })
          }.padding({ left: 10 })
        }, (item: ContactGroup) => item.title)
      }.sticky(StickyStyle.Header)
      .width('100%')
      .height('100%')
      .onScrollIndex((startIndex) => {
        this.scrollIndex = startIndex
      })

      AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
        .selected(this.scrollIndex + 1)
        .itemSize(20)
        .margin({ right: 20 })
        .onSelect((index) => {
          this.scroller.scrollToIndex(index)
        })
    }.alignContent(Alignment.End)
  }

  @Builder itemEnd(groupIndex: number, itemIndex: number) {
    Button({ type: ButtonType.Normal }) {
      Text('Delete').padding(10).fontColor(Color.White)
    }
    .backgroundColor(Color.Red)
    .height(50)
    .onClick(() => {
      console.log(`${groupIndex}:${itemIndex}index`)
      this.contactList[groupIndex].contactGroup.splice(itemIndex, 1)
    })
  }

  @Builder getGroupHeader(title: string) {
    Text(title)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }
}

@Component
struct ContactItem {
  [@ObjectLink](/user/ObjectLink) group: ContactGroup
  private index: number
  build() {
    Row() {
      Image(this.group[this.index].headPic).width(50).height(50).margin({ top: 10, left: 20 })
      Text(this.group[this.index].name).fontSize(18).padding(5)
    }.width('100%')
  }
}

LazyForEach 使用 dataSource 吧,列表数据量大了,这样用会很卡的。

我现在是在学习阶段,都要了解一下。遇到的问题是为什么@Observed@ObjectLink为什么会报错?是因为groupInfo和ContactItem({group: groupInfo, index: itemIndex})不在一个层级吗?

在HarmonyOS鸿蒙Next中,使用ListListItemGroup删除分组里的一个item,可以通过以下步骤实现:

  1. 获取数据源:首先,确保你有一个数据源,通常是一个数组或列表,用于存储ListItemGroup中的item

  2. 绑定数据源:将数据源绑定到List组件,并通过ListItemGroup来管理分组。

  3. 删除操作:在需要删除item时,直接从数据源中移除对应的项,然后通知List组件刷新。

以下是一个简单的代码示例:

// 假设数据源是一个数组
let dataSource = [
  { group: 'Group1', items: ['Item1', 'Item2', 'Item3'] },
  { group: 'Group2', items: ['Item4', 'Item5', 'Item6'] }
];

// 绑定数据源到List
@Entry
@Component
struct MyList {
  @State data: Array<any> = dataSource;

  build() {
    List({ space: 10 }) {
      ForEach(this.data, (group, groupIndex) => {
        ListItemGroup({ header: group.group }) {
          ForEach(group.items, (item, itemIndex) => {
            ListItem() {
              Text(item)
                .onClick(() => {
                  // 删除操作
                  this.data[groupIndex].items.splice(itemIndex, 1);
                  this.data = [...this.data]; // 触发UI更新
                })
            }
          })
        }
      })
    }
  }
}

在这个示例中,点击某个item时,会从对应的ListItemGroup中删除该item,并通过更新data来触发List组件的刷新。

回到顶部