HarmonyOS鸿蒙Next中class对象数组(a)里面有对象数组(b),其中a用来展示纵向列表,b用来在a里面展示横向列表,当我更新了b对象数组,UI无法更新

HarmonyOS鸿蒙Next中class对象数组(a)里面有对象数组(b),其中a用来展示纵向列表,b用来在a里面展示横向列表,当我更新了b对象数组,UI无法更新 上图为效果图

下面是代码

@Entity({
  tableName: 'routine_enum_entity',
})
@Observed
export class RoutineEnumEntity {
  @Columns({
    name: 'id',
    type: ColumnType.TEXT,
    isPrimaryKey: true,
  })
 id: string|null = null; // 主键
  @Columns({ name: 'dic_text', type: ColumnType.TEXT })
  dicText: string | null = null;
  @Columns({ name: 'dic_value', type: ColumnType.TEXT })
   dicValue: string | null = null;
  @Columns({ name: 'dic_code', type: ColumnType.TEXT })
 dicCode: string | null = null;
  @Columns({ name: 'create_time', type: ColumnType.TEXT })
   createTime: string | null = null;

   photoList: PhotoEntity[] = [];
}

@Entry
@Component
struct RoutineCheckListPage {
  @State controller: RefreshController = new RefreshController(); // 刷新控制器,声明全局变量
  @State routineViewModel: RoutineViewModel = new RoutineViewModel();
  @State titleModel: TitleBar.Model = new TitleBar.Model()
    .setOnLeftClickListener(() => {
      router.back();
    });
  @State enumList: RoutineEnumEntity[] = [];
  @State dicValue: string = '';
  @State dicCode: string = '';
  @State maxTitleHeight: number = -1;
  @State maxItemAllHeight: number = -1;
  private context = getContext() as common.UIAbilityContext;
  private filePath = "";

  /// 获取项目列表
  getEnumList() {
    this.routineViewModel.getEnumNextList(this.dicValue).then(values => {
      this.enumList = [...values];
      this.controller.finishRefresh();
    });
  }

  aboutToAppear(): void {
    this.filePath = `${this.context.filesDir}/${CommonConstants.CONTRACT_ID}&${CommonConstants.MODULE_ID}`;
    const params = (router.getParams() as ParamsEntity);
    this.dicValue = params.type!;
    this.dicCode = params.code!;
    this.titleModel.titleName = params.titleName!;
    this.getEnumList();
  }

  build() {
    Column() {
      TitleBar({ model: this.titleModel })
        .padding({ top: 40 })
        .backgroundColor($r('app.color.white'));
      ListView({
        items: this.enumList, // 数据源 数组, 任意类型
        itemLayout: (item) => this.itemLayout(item as RoutineEnumEntity),
        controller: this.controller, // 控制器,负责关闭下拉和上拉
        isLazyData: false, // 禁止懒加载,也就是使用 ForEach 进行数据加载
        onRefresh: () => {
          // 下拉刷新
          this.getEnumList();
        }
      }).layoutWeight(1);
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.common_f5f6f6'));
  }

  // 相册选择图片/视频
  selectDefault(photoList:PhotoEntity[]) {
    DialogHelper.showActionSheetDialog({
      title: "请选择上传方式",
      sheets: ["相机", "从手机相册选择"],
      onAction: (index) => {
        if (index == 0) {
          let options: CameraOptions = {
            mediaTypes: [cameraPicker.PickerMediaType.PHOTO],
            cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,
            saveUri: this.filePath, // 图片保存路径
          };
          PickerUtil.camera(options).then(result => {
            LogUtil.debug(`调用相机,返回 uri:\n${result.resultUri}`);
            const newPhoto = new PhotoEntity();
            newPhoto.fileUri = result.resultUri;
            photoList = [...photoList, newPhoto]; // 使用新数组替换旧数组
          }).catch(err: BusinessError => {
            showToast(`调用相机异常:\n${JSON.stringify(err)}`);
          });
        } else {
          PhotoHelper.select().then(uris => {
            let ps: Permissions[] = ['ohos.permission.WRITE_IMAGEVIDEO'];
            PermissionUtil.requestPermissions(ps).then(result => {
              if (result) {
                uris.forEach((uri, index) => {
                  LogUtil.debug(`photoList1:\n${uri}`);
                  ImageHelper.compressPhoto(uri, this.filePath, index)
                    .then(compressUri => {
                      const newPhoto = ImageHelper.savePhotoEntity(uri, compressUri);
                      photoList = [...photoList, newPhoto]; // 使用新数组替换旧数组
                      LogUtil.debug('photoList2,' + JSON.stringify(photoList));
                    });
                });
              } else {
                showToast("请在设置中打开权限");
                WantUtil.toAppSetting();
              }
            });
          });
        }
      }
    });
  }

  /**
   * Author: AbnerMing
   * Describe: 条目布局
   * @param item  数据对象
   * @param index  数据索引
   */
  @Builder
  itemLayout(item: RoutineEnumEntity): void {
    // 条目视图,任意组件
    RelativeContainer() {
      Column() {
        Row() {
          Text(item.dicText)
            .fontSize(14)
            .fontColor($r('app.color.common_333333'))
            .margin(10)
            .layoutWeight(1);
          Image($r('app.media.ic_right'))
            .height(20)
            .padding({ right: 10 });
        }
        .width('100%')
        .backgroundColor($r('app.color.white'))
        .height(this.maxTitleHeight == -1 ? undefined : this.maxTitleHeight)
        .onAreaChange((oldArea: Area, newArea: Area) => {
          if (this.maxTitleHeight < newArea.height) {
            this.maxTitleHeight = newArea.height as number;
          }
        })
        .onClick(() => {
          router.pushUrl({
            url: RoutePath.RoutineDefectBindingPage,
            params: {
              type: item.dicValue,
            }
          });
        });
        Row() {
          RelativeContainer() {
            Image($r('app.media.ic_camera_a'))
              .width(40)
              .height(40)
              .alignRules({
                center: { anchor: '__container__', align: VerticalAlign.Center },
                middle: { anchor: '__container__', align: HorizontalAlign.Center }
              });
          }
          .width(90)
          .height(90)
          .align(Alignment.Center)
          .borderRadius(2)
          .borderStyle(BorderStyle.Dotted)
          .borderWidth(1)
          .borderColor($r('app.color.common_gray_66'))
          .stateStyles({
            normal: {
              .backgroundColor($r('app.color.common_f5f6f6'))
            },
            pressed: {
              .backgroundColor($r('app.color.white'))
            },
          })
          .onClick(() => {
            this.selectDefault(item.photoList);
          })
          .backgroundColor($r('app.color.common_main_color'));
          ListView({
            items: item.photoList, // 数据源 数组, 任意类型
            itemLayout: (item) => this.childListItemBuild(item as PhotoEntity),
            controller: this.controller, // 控制器,负责关闭下拉和上拉
            isLazyData: false, // 禁止懒加载,也就是使用 ForEach 进行数据加载
            isRefreshSticky: false,
            enableRefresh: false,
            enableLoadMore: false,
            listAttribute: (attr) => {
              attr.listDirection = Axis.Horizontal;
            }
          })
            .layoutWeight(1)
            .width('100%') // 确保宽度设置为 100%
            .height('auto') // 使用 'auto' 确保高度自适应内容
        }
        .margin(10)
        .width('100%') // 确保宽度设置为 100%
        .height('auto') // 使用 'auto' 确保高度自适应内容
        .alignItems(VerticalAlign.Top);
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)
      .backgroundColor($r('app.color.common_f5f6f6'));
    }
    .height(this.maxTitleHeight + 100)
    .borderRadius(10)
    .margin({ top: 10 })
    .backgroundColor($r('app.color.common_f5f6f6'))
    .align(Alignment.Center);
  }

  @Builder
  childListItemBuild(photo: PhotoEntity) {
    RelativeContainer() {
      Image(photo.fileUri)
        .width('100%')
        .height(90)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        }).borderRadius(10);
    }.height(100).width(90).margin({left: 10})
  }
}
@Entity(
{
  tableName: 'photo_file',
  index: [
    {
      name: 'idIndex',
      columnName: ['id'],
      unique: true
    }
  ]
}
)
@Observed
export class PhotoEntity {

  @Columns({
    name: 'id',
    type: ColumnType.TEXT
  })
  id: string | null = null; // 唯一标识

  @Columns({
    name: 'file_uri',
    type: ColumnType.TEXT
  })
  fileUri: string | null = null; // 照片路径URI
}

更多关于HarmonyOS鸿蒙Next中class对象数组(a)里面有对象数组(b),其中a用来展示纵向列表,b用来在a里面展示横向列表,当我更新了b对象数组,UI无法更新的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

使用v2装饰器试试,嵌套对象的更新v1不是很好用

更多关于HarmonyOS鸿蒙Next中class对象数组(a)里面有对象数组(b),其中a用来展示纵向列表,b用来在a里面展示横向列表,当我更新了b对象数组,UI无法更新的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


你好:

请参考:

[【HarmonyOS NEXT】@Observed和@ObjectLink嵌套对象属性更改UI不刷新问题 | 华为开发者联盟](https://developer.huawei.com/consumer/cn/blog/topic/03170446044769034)

[【HarmonyOS NEXT】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化 | 华为开发者联盟](https://developer.huawei.com/consumer/cn/blog/topic/03164568848167010)

给a对象的第一个数据重新赋值试一下勒,不要单独修改a对象里的某个b对象

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

想请教一下@column是什么写法呢?好像从来没用过这种方式,是TS的装饰器语法糖?还是仓颉的语法呢?

希望给一个官方链接,想要学习了解下。

@Columns 为dbStore数据库注解,

  • 字段名:id

  • 类型:int

  • 备注:主键自增

  • 字段名:name

  • 类型:string

  • 备注:名称

  • 字段名:age

  • 类型:int

  • 备注:年龄

鸿蒙自己的数据库还是外部数据库呢

基于sqlite封装的,

在HarmonyOS鸿蒙Next中,如果更新了对象数组b但UI未刷新,可能是因为数据绑定未正确触发。确保以下几点:

  1. 数据绑定:确保ab都使用了@State@Observed装饰器,以便在数据变化时自动更新UI。
  2. 列表组件:使用ForEachLazyForEach来渲染列表,确保列表项在数据变化时重新渲染。
  3. 更新方法:在更新b时,使用this.b = [...this.b]this.b.splice(index, 1, newItem)等方式,确保数组引用变化,触发UI更新。
  4. 状态管理:如果使用@State,确保在父组件中正确管理状态,避免状态丢失。

通过这些步骤,可以确保UI在数据更新时正确刷新。

回到顶部