HarmonyOS鸿蒙Next中@Bulider不更新

HarmonyOS鸿蒙Next中@Bulider不更新 大佬们老师们好!
下面是demo是我模拟我们壳工程的现阶段的状态

有2个前提条件
@Entry内容不允许改变
NativeDragListViewMidea只能是Builder函数导出
前面这2个是因为我们使用的是同层渲染Web()渲染 然后映射标签 使用的new WrappedBuilder创建的组件

是否能在MideaDragListViewMidea组件里面修改?我现在就是params数据修改监听不到 复现的话 demo顶上的按钮点击切换数据是有变化的ui不会变

import curves from '[@ohos](/user/ohos).curves'
import lottie, { AnimationItem } from '[@ohos](/user/ohos)/lottie'
import ObjectUtil from './utils'

interface globalFace {
  visibility?: number;
  alpha?: number;
  width?: number;
  height?: number;
  margin?: number[]; //view的外边距数组,大小为4. left,top,right,bottom
  padding?: number[]
  textColor?: string,
  textSize?: number,
  fontWeight?: number | string
  fontFamilyPath?: string
  cornerRadius?: number
  backgroundColor?: string
}

interface globalLottleFace {
  animUrl?: string //lottie动画链接
  animRepeatCount?: number
  width?: number
  height?: number
}

interface itemViewFace {
  id: number | string;
  url?: string; //图片链接
  text?: string;
  animUrl?: string; //动画链接
  enable?: boolean; // 可以被选中 被删除被复制 ?
  backgroundColor?: string;
  isSelected?: boolean; //是否选中
  animRepeatCount?: number; //动画重复次数
  isEditable?: boolean; //是否可编辑
  visibility?: number; //view的显示属性。0-隐藏,1-显示,2-隐藏但保留占位
  textColor?: string; //字体颜色
  textSize?: number; //字体大小
  fontFamilyPath?: string; //字体家族
  fontFamilyName?: string; //字体名称
  width?: number; //-1表示match_parent, -2表示wrap_content, >=0表示具体的大小 现阶段处理-1 -2就自适应
  height?: number
  margin?: number[]
  padding?: number[]
  alpha?: number; //透明度
  cornerRadius?: number
  selectedBorderColor?: string //选中时列表项的边框颜色。默认是
  normalBorderColor?: string //未选中时列表项的边框颜色。默认是
  selectedBorderWidth?: number //选中时列表项的边框宽度。默认是0
  normalBorderWidth?: number //未选中时列表项的边框宽度。默认是0
}

interface textFace extends globalFace {
  text?: string;
}

interface leftIconFace extends globalFace {
  url?: string;
}

interface iconFace {
  alpha?: number;
  url?: string;
  visibility?: number
  width?: number;
  height?: number;
  margin?: number[]
  padding?: number[]
}

interface rightIconFace extends globalFace {
  url?: string
}

interface selectIconFace extends globalFace {
  url?: string
  selectedUrl?: string //选择图标,需要配置selectedUrl,默认不可见就行,进入编辑状态会主动展示
}

interface loadingAnimViewFace extends globalFace, globalLottleFace {}

interface bgAnimViewFace extends globalFace, globalLottleFace {}

interface frontAnimViewFace extends globalFace, globalLottleFace {}

interface buttonFace extends globalFace {
  url?: string
  textColor?: string; //文字颜色
  textSize?: number; //文字大小
  backgroundColor?: string;
  cornerRadius?: number
  text?: string
  fontWeight?: string | number
}

interface listFace {
  itemView: itemViewFace,
  text: textFace,
  leftTopIcon: leftIconFace,
  iconImage: iconFace,
  rightIcon: rightIconFace,
  selectIcon: selectIconFace,
  actionButton: buttonFace
}

interface layoutFace {
  marginStart: number,
  marginEnd: number,
  marginTop: number,
  marginBottom: number
}

interface bgImgFace extends globalFace {
  url?: string;
}

interface MideaDragListData {
  id?: string | number,
  isEditable?: boolean,
  itemView?: itemViewFace,
  text?: textFace,
  leftTopIcon?: leftIconFace,
  iconImage?: iconFace,
  rightIcon?: rightIconFace,
  selectIcon?: selectIconFace,
  actionButton?: buttonFace,
  bgImage?: bgImgFace //背景图片
  loadingAnimView?: loadingAnimViewFace //点击执行loading动画
  bgAnimView?: bgAnimViewFace //执行中的动画
  frontAnimView?: frontAnimViewFace //执行成功动画
  enable?: boolean //是否可操作
}

interface MideaDragListViewMideaParamsFace {
  itemViewHeight?: number, // 高度
  spanCount?: number, //列数
  spaceSize?: number, //列间距
  isEditable?: boolean, //控制整个列表是否可编辑,默认是false, 为true时才显示编辑按钮
  isEditing?: boolean, //是否处于编辑状态
  layoutConfig?: layoutFace,
  list?: MideaDragListData[],
  globalData?: MideaDragListData //全局默认参数 每个对象的默认值
}

[@Observed](/user/Observed)
class MideaDragListViewMideaParams {
  data: MideaDragListViewMideaParamsFace
  componentId: string
  width?: number
  height?: number

  constructor() {
    this.data = {
      list: []
    }
    this.componentId = ''
  }
}

[@Component](/user/Component)
struct MideaDragListViewMidea {
  [@ObjectLink](/user/ObjectLink)
  [@Watch](/user/Watch)('paramsWatchFn') //监听
  params: MideaDragListViewMideaParams
  private canvasContextMap: Map<string, CanvasRenderingContext2D> = new Map()
  private animationMap: Map<string, AnimationItem> = new Map()
  [@State](/user/State) myRotate: number = 0; // 旋转角度
  [@State](/user/State) list: MideaDragListData[] = [] // 列表项数组
  [@State](/user/State) selectedItem: MideaDragListData | undefined = {} // 选中项,初始值为undefined
  private globalPositionY: number = 0 // 全局Y位置,初始值为0
  [@State](/user/State) domWidth: number = 0 // 构建器尺寸
  [@State](/user/State) domHeight: number = 0 // 构建器尺寸
  [@State](/user/State) containerHeight: number = 0 // 容器高度
  [@State](/user/State) containerWidth: number = 0 // 容器宽度
  // 拖动元素初始位置
  [@State](/user/State) dragStartX: number = 0 // 拖动开始的X位置
  [@State](/user/State) dragStartY: number = 0 // 拖动开始的Y位置
  // 拖动元素偏移距离
  [@State](/user/State) offsetX: number = 0 // 拖动偏移的X距离
  [@State](/user/State) offsetY: number = 0 // 拖动偏移的Y距离
  // 拖动后滚动距离
  [@State](/user/State) scrollLen: number = 0 // 滚动距离
  [@State](/user/State) dragOffsetX: number = 0 // 拖动后的X偏移
  [@State](/user/State) dragOffsetY: number = 0 // 拖动后的Y偏移
  private scroller: Scroller = new Scroller(); // 滚动控制器
  [@State](/user/State) spanCount: number = 4
  private componentId: string = ''
  timer: number = -1

  init() {
    this.spanCount = this.params?.data?.spanCount ?? 4
    this.list = this.params?.data?.list || []
    console.info('list', this.list)
    if (this.params.data.isEditing) {
      this.animationTo()
    }
    this.initList(this.params?.data?.globalData || {})
  }

  initList(data: MideaDragListData) {
    this.list= this.list.map(item => {
      item.text = ObjectUtil.Assign(data?.text || {}, item.text)
      item.actionButton = ObjectUtil.Assign(data?.actionButton || {}, item.actionButton)
      item.leftTopIcon = ObjectUtil.Assign(data?.leftTopIcon || {}, item.leftTopIcon)
      item.iconImage = ObjectUtil.Assign(data?.iconImage || {}, item.iconImage)
      item.rightIcon = ObjectUtil.Assign(data?.rightIcon || {}, item.rightIcon)
      item.selectIcon = ObjectUtil.Assign(data?.selectIcon || {}, item.selectIcon)
      item.bgImage = ObjectUtil.Assign(data?.bgImage || {}, item.bgImage)
      item.loadingAnimView = ObjectUtil.Assign(data?.loadingAnimView || {}, item.loadingAnimView)
      item.bgAnimView = ObjectUtil.Assign(data?.bgAnimView || {}, item.bgAnimView)
      item.frontAnimView = ObjectUtil.Assign(data?.frontAnimView || {}, item.frontAnimView)
      item.itemView = ObjectUtil.Assign(data?.itemView || {} as itemViewFace, item.itemView)
      item.id = item.itemView.id
      return item
    }, (item: MideaDragListData) => {
      return `${item?.itemView?.id}-${item?.itemView?.isSelected}`
    })
    console.log('cdj---list', JSON.stringify(this.list))
  }

  animationTo() {
    clearInterval(this.timer)
    this.timer = setInterval(() => {
      animateTo({ curve: curves.interpolatingSpring(0, 1, 1000, 138) }, () => {
        this.myRotate = this.myRotate === -6 ? 6 : -6;
      })
    }, 140);
  }

  // 页面隐藏时统一清理
  onPageHide() {
    console.log('onPageHide')
    this.animationMap.forEach(anim => anim.destroy())
    this.animationMap.clear()
    lottie.destroy()
  }

  aboutToAppear(): void {
    this.init()
    this.componentId = this.params?.componentId;
  }

  paramsWatchFn() {
    console.info('this?.params?.data', JSON.stringify(this?.params?.data))
    this.init()
    this.domWidth = (this.containerWidth) / this.spanCount;
    if (!this.params.data.isEditing) {
      clearInterval(this.timer)
      this.myRotate = 0
    }
  }

  [@Builder](/user/Builder)
  MideaToggle($$: MideaDragListData) {
    Image($$?.itemView?.isSelected ?
      ($$?.selectIcon?.selectedUrl || this.params?.data?.globalData?.selectIcon?.selectedUrl)
      : ($$?.selectIcon?.url || this.params?.data?.globalData?.selectIcon?.url)
    )
      .draggable(false).attributeModifier(new defaultAttr($$?.selectIcon as globalFace))
      .onClick(() => {
        console.log('item.itemView.isSelected', $$?.itemView?.isSelected)
        if ($$?.itemView) {
          $$.itemView.isSelected = !$$.itemView.isSelected;
        }
        this.onSelectItems()
        this.updateListItem($$)
      })
  }

  [@Builder](/user/Builder)
  MideaButton(item: MideaDragListData) {
    Button(item?.actionButton?.text ).draggable(false)
      .attributeModifier(new defaultAttr(item?.actionButton as globalFace))
      .onClick(() => {
        console.log('我是儿子')
      })
  }

  [@Builder](/user/Builder)
  MideaRightIcon(item: MideaDragListData) {
    Image(item?.rightIcon?.url).draggable(false)
      .attributeModifier(new defaultAttr(item?.rightIcon as globalFace))

  }

  [@Builder](/user/Builder)
  ItemBuilder($$: MideaDragListData) {
    Flex({
      direction: FlexDirection.Column,
      justifyContent: FlexAlign.SpaceAround
    }) {
      if (!this.params.data.isEditing) {
        this.LottieBox('bgAnimView', $$?.bgAnimView)
        this.LottieBox('frontAnimView', $$?.frontAnimView)
      }
      Image($$?.leftTopIcon?.url)
        .attributeModifier(new defaultAttr($$?.leftTopIcon as globalFace))
        .position({
          left: 0,
          top: 0
        })
      Flex({
        justifyContent: FlexAlign.SpaceBetween
      }) {
        Image(
          $$?.iconImage?.url
        ).draggable(false)
          .attributeModifier(new defaultAttr($$?.iconImage as globalFace))
        if (!this.params.data.isEditing) {
          this.MideaButton($$)
          this.MideaRightIcon($$)

          this.LottieBox('loadingAnimView', $$?.loadingAnimView)
        } else {
          this.MideaToggle($$);
        }

      }

      Text($$?.text?.text)
        .attributeModifier(new defaultAttr($$?.text as globalFace))
        .textOverflow({ overflow: TextOverflow.Ellipsis })
        .maxLines(1)
    }
    .attributeModifier(new defaultAttr($$?.itemView as globalFace))
    .borderWidth($$?.itemView?.normalBorderColor || this.params?.data?.globalData?.itemView?.normalBorderColor)
    .borderColor($$?.itemView?.normalBorderWidth || this.params?.data?.globalData?.itemView?.normalBorderWidth)
    .visibility(0)
    .rotate({
      z: 1,
      angle: this.myRotate
    })
    .onClick(() => {
      console.log('我是粑粑')
    })
    .enabled($$?.itemView?.enable || this.params?.data?.globalData?.enable)
  }

  [@Builder](/user/Builder)
  dragBuilder() {
    Flex() {
      if (this.selectedItem?.itemView?.id) {
        this.ItemBuilder(this.selectedItem)
      }
    }
    .hitTestBehavior(HitTestMode.None)
    .zIndex(1)
    .width(this.domWidth)
    .position({ x: this.dragStartX + this.offsetX, y: this.dragStartY + this.offsetY - this.globalPositionY })
    .onAreaChange((_, newValue) => {
      if (this.selectedItem === undefined) {
        return
      }
      if (newValue.position.y && newValue.position.y < 0) {
        this.scroller.scrollEdge(Edge.Top, { velocity: 300 })
      } else if (newValue.position.y && newValue.position.y > this.containerHeight - this.domHeight) {
        this.scroller.scrollEdge(Edge.End, { velocity: 300 })
      } else {
        this.scroller.scrollTo(this.scroller.currentOffset())
      }
    })
  }

  reset() {
    this.selectedItem = {}
    this.scrollLen = 0
    this.dragStartX = 0
    this.dragStartY = 0
    this.dragOffsetX = 0
    this.dragOffsetY = 0
    this.offsetX = 0
    this.offsetY = 0
    this.scroller.scrollTo(this.scroller.currentOffset())
  }

  itemMove(index: number, newIndex: number) {
    let tmp = this.list.splice(index, 1)
    this.list.splice(newIndex, 0, tmp[0])
  }

  getIndex() {
    let index = -1;
    index = this.list.findIndex(item => item?.itemView?.id == this?.selectedItem?.itemView?.id)
    return index
  }

  handleDrag() {
    const index = this.getIndex();
    if (index < 0) {
      return;
    }
    const boundaryA = this.spanCount + 1; //边界   5
    const boundaryB = this.spanCount; //边界   4
    const boundaryC = this.spanCount - 1; //边界   3

    let x = this.offsetX - this.dragOffsetX; //当前位置 = 移动后的位置 - 点击位置
    let y = this.scrollLen + this.offsetY - this.dragOffsetY; // 当前位置 = y轴滚动偏差 + 移动后的位置 - 点击位置

    //拉到容器外需要限制一下
    y = y > this.domHeight ? this.domHeight : y
    x = x > (this.containerWidth - (this.domWidth / 2)) ? (this.containerWidth - (this.domWidth / 2)) : x

    let itemWidth = this.domWidth; //拖拽容器宽度的边界
    let translateWidth = itemWidth / 2; // 拖拽容器中心位置
    let slashLength = itemWidth / 2; // 实际容器边界
    let itemHeight = this.domHeight; // 拖拽容器高度的边界
    let translateHeight = itemHeight / 2; // 拖拽容器中心位置
    let slashHeight = itemHeight / 2; // 实际容器边界
    const z = (str: number) => Number.parseInt(str.toString())
    const getLog = (text: string) => {
      console.info(text, JSON.stringify({
        index,
        y: z(y),
        x: z(x),
        offsetX: z(this.offsetX),
        offsetY: z(this.offsetY),
        dragOffsetY: z(this.dragOffsetY),
        dragOffsetX: z(this.dragOffsetX),
        containerWidth: z(this.containerWidth)
      }));
    };
    //交换的时候 中间间隔多少个兄弟元素
    const offest = (index % boundaryB) - (this.list.length % boundaryB)

    console.info('日志1', JSON.stringify({
      x,
      offest,
      xxx: x * offest,
      y,
      translateWidth,
      translateHeight,
      offsetX: this.offsetX,
      dragOffsetX: this.dragOffsetX,
      dragOffsetY: this.dragOffsetY
    }))


    if (y >= translateHeight && (x < slashLength && x > -slashLength)) {
      // 从上移动到下 元素向前补位
      if (index + boundaryA > (this.list.length)) {
        return
      }
      this.itemMove(index, index + boundaryB)
      this.dragOffsetY += itemHeight;
      getLog('上到下');
    } else if (y <= -translateHeight && (x < slashLength && x > -slashLength)) {
      // 从下到上
      if (index < boundaryB) {
        return
      }

      this.itemMove(index, index - boundaryB)
      this.dragOffsetY -= itemHeight;
      getLog('下到上');
      console.info('下到上', index, index - boundaryB)
    } else if (x >= translateWidth && (y < slashHeight && y > -slashHeight)) {
      // 从左到右
      if (index + 1 >= this.list.length) { //边界不动 不补位
        return;
      }
      this.itemMove(index, index + 1);
      this.dragOffsetX += itemWidth;
      getLog('左到右');
    } else if (x <= -translateWidth && (y < slashHeight && y > -slashHeight)) {
      // 从右到左
      if (index % boundaryB === 0) {
        return
      }
      this.itemMove(index, index - 1)
      this.dragOffsetX -= itemWidth;
      getLog('右到左');
    } else if (x >= translateWidth && y >= translateHeight) {
      // 右下移动
      if (index % boundaryB === boundaryC || index + boundaryA > this.list.length) {
        return
      }
      this.itemMove(index, index + boundaryA)
      this.dragOffsetX += itemWidth;
      this.dragOffsetY += itemHeight;
      getLog('右下角');
    } else if (x >= translateWidth && y <= -translateHeight) {
      // 右上移动
      if (index % boundaryB === boundaryC || (index - boundaryC < 0)) {
        return;
      }
      this.itemMove(index, index - boundaryC);
      this.dragOffsetX += itemWidth;
      this.dragOffsetY -= itemHeight;
      getLog('右上角');
    } else if (x <= -translateWidth && y <= -translateHeight) {
      // 左上
      if (index % boundaryB === 0 || (index - boundaryA < 0)) {
        return
      }
      this.itemMove(index, index - boundaryA)
      this.dragOffsetX -= itemWidth;
      this.dragOffsetY -= itemHeight;
      getLog('左上角');
    } else if (
      x <= -(translateWidth + (this.domWidth * offest)) && y >= translateHeight) {
      console.info('左下', JSON.stringify({
        x,
        offest,
        xxx: x * offest,
        y,
        translateWidth,
        domWidth: this.domWidth,
        translateHeight,
        offsetX: this.offsetX
      }))
      if (index % boundaryB === 0) {
        return
      }
      this.itemMove(index, this.list.length)
      // 记录交换后的位置 -自身宽度以及间隔元素宽度  只有在最后一行不填满的情况 并且是倒数第二行交换的时候才需要计算
      this.dragOffsetX -= (itemWidth + (itemWidth * offest));
      this.dragOffsetY += itemHeight;
      console.info('dragOffsetY~~~', this.dragOffsetY)
    }
    console.info('dddd', JSON.stringify({
      x,
      offest,
      xxx: x * offest,
      y,
      translateWidth,
      translateHeight,
      offsetX: this.offsetX,
      dragOffsetX: this.dragOffsetX,
      dragOffsetY: this.dragOffsetY
    }))

  }

  // 设计事件
  updateListItem(data: MideaDragListData): void {

    const id = data?.itemView?.id
    if (!id) {
      return;
    }
    const index = this.list.findIndex(item => item.itemView?.id === id);
    if (index === -1) {
      return;
    }

    // 创建新对象
    const newItem = data as MideaDragListData;

    // 替换数组元素
    this.list.splice(index, 1, newItem);

    this.list = this.list.slice();
  }

  private getListData() {
    return this.list
  }

  onSelectItems() { //是编辑状态下,选中的 item的 id 数组 返回的是ids:["21675327"]
    const selectedIds = this.list
      .filter(item => item?.itemView?.isSelected)
      .map(item => item?.itemView?.id);
    console.log('cdj------selectedIds', selectedIds,)
  }

  //lottie动画相关----------------------------
  [@Builder](/user/Builder)
  LottieBox(name: string, item?: globalLottleFace) {
    Canvas(this.createCanvasContext(name))
      .onReady(() => {
        const ctx = this.createCanvasContext(name)
        ctx.imageSmoothingEnabled = true
        ctx.imageSmoothingQuality = 'medium'
        if (!this.animationMap.has(name)) {
          this.loadAnimation(name, item as globalLottleFace)
        }
      })
      .attributeModifier(new defaultAttr(item as globalFace))// .zIndex(name === 'frontAnimView' ? 100 : 0)
      .position(name !== 'loadingAnimView' ? {
        right: 0,
        top: 0,
        bottom: 0,
        left: 0
      } : {})
  }

  // 创建并缓存 Canvas 渲染上下文
  createCanvasContext(name: string): CanvasRenderingContext2D {
    if (!this.canvasContextMap.has(name)) {
      const settings = new RenderingContextSettings(true)
      const context = new CanvasRenderingContext2D(settings)
      this.canvasContextMap.set(name, context)
    }
    return this.canvasContextMap.get(name)!
  }

  // 加载动画
  loadAnimation(name: string, item: globalLottleFace) {
    const context = this.createCanvasContext(name)
    this.animationMap.get(name)?.destroy()
    const animation = lottie.loadAnimation({
      container: context,
      renderer: 'canvas',
      autoplay: true,
      loop: item?.animRepeatCount,
      name,
      contentMode: name !== 'loadingAnimView' ? 'Fill' : 'Contain',
      uri: item?.animUrl
    })

    this.animationMap.set(name, animation)
  }

  build() {
    Column() {
      Button('切换编辑状态').onClick(() => {
        this.params.data.isEditing = !this.params.data.isEditing
        console.log('编辑状态', this.params.data.isEditing)
      })
      Text(`${this.params.data.isEditing}`)

      Column() {
        if (this?.selectedItem?.itemView?.id !== undefined) {
          this.dragBuilder()
        }
        Scroll(this.scroller) {
          Column() {
            Grid() {
              ForEach(this.list, (item: MideaDragListData) => {
                GridItem() {
                  this.ItemBuilder(item)
                }
                .opacity(this.selectedItem?.itemView?.id === item?.itemView?.id ? 0 : 1)
                .onClick((event) => {

                })
                .gesture( //手势事件
                  GestureGroup(GestureMode.Sequence,
                    LongPressGesture({ repeat: true })//长按手指事件
                      .onAction((event?: GestureEvent) => {
                        console.log('cdj==', JSON.stringify(event?.target))
                        if (!this.params.data.isEditable) {
                          return
                        }
                        if (this.params.data.isEditable) {
                          this.animationTo()
                        }
                        this.params.data.isEditing = true
                        //点击坐标
                        if (this.selectedItem?.itemView?.id === undefined) {
                          this.selectedItem = item
                          this.dragStartX = Number(event?.target.area.globalPosition.x)
                          this.dragStartY = Number(event?.target.area.globalPosition.y)
                        }
                      })
                      .onActionEnd(() => {
                        this.reset()
                      }),
                    PanGesture({ fingers: 1, direction: null, distance: 0 })//1指拖动时
                      .onActionStart((event) => { //开始拖动
                        if (!this.params.data.isEditable) {
                          return
                        }
                        this.scrollLen = 0
                        this.selectedItem = item
                      })
                      .onActionUpdate(event => { //拖动过程中

                        this.offsetY = event.offsetY
                        this.offsetX = event.offsetX
                        //curve 动画曲线 速度 弹性 刚度 阻尼
                        animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                          this.handleDrag()
                        })
                      })
                      .onActionEnd((event) => { //抬起 结束
                        this.reset()
                      })
                  )
                    .onCancel(() => {
                      this.reset()
                    })
                )
              }, (item: MideaDragListData) => {
                return `${item?.itemView?.id}-${item?.itemView?.isSelected}`
              })
            }
            .columnsTemplate(`repeat(${this.spanCount}, 1fr)`)
            .columnsGap(this.params.data.spaceSize ?? 10) // 列与列间距
            .rowsGap(10) // 行与行
          }
          .padding(10)
          .alignItems(HorizontalAlign.Start)
        }
        .width(this.params.width)
        .height(this.params.height || 400)
        .align(Alignment.Top)
        .scrollBar(BarState.Off) //隐藏滚动条
        .onDidScroll((x, y) => {
          if (this?.selectedItem?.itemView?.id !== undefined) {
            this.scrollLen += y //滚动距离
            // this.handleDrag()
          }
        })
        .onAreaChange((_, newValue) => {
          if (!this?.params?.data?.list?.length) {
            return
          }
          console.info('this.globalPositionY ', JSON.stringify(newValue))
          //初始化
          this.globalPositionY = Number(newValue.globalPosition.y)
          this.containerWidth = Number(newValue.width)
          this.containerHeight = Number(newValue.height)
          this.domWidth = (this.containerWidth) / this.spanCount;
          const size = this?.params?.data?.spaceSize ?? 10
          const dowSize = (size * this.spanCount) + size
          console.log('newValue.height', this.containerHeight, this?.params?.data?.spaceSize, this.spanCount,
            this?.params?.data?.list?.length)

          this.domHeight = (this.containerHeight - dowSize) / (this?.params?.data?.list?.length / this.spanCount) ?? 60
          // 高度减去间距 / 长度/行数得到每列几个
          console.info('domWidth', this.domWidth)
          console.info('containerHeight', this.containerHeight)

        })
      }
      .clip(true)
    }
  }
}

[@Observed](/user/Observed)
class defaultAttr implements AttributeModifier<ButtonAttribute | TextAttribute | FlexAttribute> {
  data: globalFace = {}
  visibilitArr = [Visibility.None, Visibility.Visible, Visibility.Hidden] // 0-隐藏,1-显示,2-隐藏但占位

  constructor(item: globalFace) {
    this.data = item || {}
    console.log('init', item)
  }

  applyNormalAttribute(instance: ButtonAttribute | TextAttribute | FlexAttribute | CanvasAttribute): void {
    try {
      const fontStyle = instance as ButtonAttribute | TextAttribute
      fontStyle.fontColor(this.data?.textColor ?? '#000000')
      fontStyle.fontWeight(this.data?.fontWeight)
      fontStyle.fontFamily(this.data?.fontFamilyPath)
      fontStyle.fontSize(this.data?.textSize ?? 16)
    } catch (e) {}

    instance.visibility(
      this.visibilitArr[this.data.visibility ?? 1]
    )
    instance.width(this.data?.width )
    instance.backgroundColor(this.data?.backgroundColor)
    instance.height(this.data?.height )
    instance.borderRadius(this.data?.cornerRadius)

    instance.margin({
      top: this.data?.margin?.[1] ?? 0,
      left: this.data?.margin?.[0] ?? 0,
      right: this.data?.margin?.[2] ?? 0,
      bottom: this.data?.margin?.[3] ?? 0
    })

    instance.padding({
      top: this.data?.padding?.[1] ?? 0,
      left: this.data?.padding?.[0] ?? 0,
      right: this.data?.padding?.[2] ?? 0,
      bottom: this.data?.padding?.[3] ?? 0
    })

    instance.opacity(this.data?.alpha)
  }
}

[@Builder](/user/Builder)
export function NativeDragListViewMidea($$: MideaDragListViewMideaParams) {
  MideaDragListViewMidea({
    params: {
      data: $$.data,
      componentId: $$.componentId,
      width: $$.width,
      height: $$.height
    }
  })
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct demo {
  initData: MideaDragListViewMideaParamsFace = {}

  aboutToAppear(): void {
    this.initData = {
      spanCount: 2, //列数
      spaceSize: 8,
      isEditable: true, //控制整个列表是否可编辑,默认是false, 为true时才显示编辑按钮
      layoutConfig: {
        marginStart: 15,
        marginEnd: 15,
        marginTop: 0,
        marginBottom: 0
      },
      list: [
        {
          "itemView": {
            "id": 21675327,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "离家场景49",
            "alpha": 1,
            "textColor": "#5e8392",
            "visibility": 1,
          },
          "leftTopIcon": {
            "visibility": 1,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 1,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/home_ic_wrong_s@2x.png"
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility": 0
          }
        },
        {
          "itemView": {
            "id": 21675325,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "离家场景48",
            "alpha": 1
          },
          "leftTopIcon": {
            "visibility": 0,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 0,
            "alpha": 1
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility": 1
          }
        },
        {
          isEditable: true,
          "itemView": {
            "id": 21674863,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "离家场景45",
            "alpha": 1
          },
          "leftTopIcon": {
            "visibility": 0,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 0,
            "alpha": 1
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility": 1
          }
        },
        {
          "itemView": {
            "id": 21675191,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "复制离家场景45",
            "alpha": 1
          },
          "leftTopIcon": {
            "visibility": 0,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 0,
            "alpha": 1
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility": 1
          }
        },
        {
          isEditable: true,
          "itemView": {
            "id": 21134863,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "离家场景45",
            "alpha": 1
          },
          "leftTopIcon": {
            "visibility": 0,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 0,
            "alpha": 1
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility": 1
          }
        },
        {
          "itemView": {
            "id": 21675391,
            "enable": true,
            "backgroundColor": "#F6F7F9",
            "isSelected": false
          },
          "text": {
            "text": "复制离家场景45",
            "alpha": 1
          },
          "leftTopIcon": {
            "visibility": 0,
            "alpha": 1,
            "url": "http://10.133.240.64:5501/dist/midea-rooms/assets/img/new2025@2x.png"
          },
          "iconImage": {
            "alpha": 1,
            "url": "https://xxx/sit/app/v1/manual_scene_icon/1.png"
          },
          "rightIcon": {
            "visibility": 0,
            "alpha": 1
          },
          "selectIcon": {
            "visibility": 1
          },
          "actionButton": {
            "visibility

更多关于HarmonyOS鸿蒙Next中@Bulider不更新的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

你好,基于你的demo做了一些简化后,提供了如下的方案,可供参考

@class MideaDragListViewMideaParams {
  @Track data: number = 0

  constructor(data: number) {
    this.data = data
  }
}

@Component
struct MideaDragListViewMidea {
  @ObjectLink @Watch('paramsWatchFn') params: MideaDragListViewMideaParams

  paramsWatchFn() {
    console.info('this?.params?.data', this.params.data)
  }

  build() {
    Column() {
      Button("改变Params")
        .onClick(() => {
          this.params.data++
        })
      Text("number = " + this.params.data)
    }
  }
}

@Builder
export function NativeDragListViewMidea(param: MideaDragListViewMideaParams) {
  MideaDragListViewMidea({
    params: param
  })
}

@Entry
@Component
struct Test7 {
  @State initData: MideaDragListViewMideaParams = new MideaDragListViewMideaParams(10)

  build() {
    Column() {
      NativeDragListViewMidea(this.initData)
    }
  }
}

更多关于HarmonyOS鸿蒙Next中@Bulider不更新的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,@Builder装饰器用于定义可复用的UI组件。如果发现@Builder不更新,可能的原因包括:

  1. 状态未更新:确保传递给@Builder的状态变量已更新。使用@State@Link等装饰器管理状态,确保状态变化时UI重新渲染。

  2. 依赖未变化:@Builder依赖于传入的参数,如果参数未变化,UI不会更新。检查参数是否正确传递并变化。

  3. 组件未重新构建:确保父组件在状态变化时重新构建,从而触发@Builder的更新。

  4. 使用@Watch监控变化:在@Builder中使用@Watch装饰器监控特定状态变量的变化,确保状态变化时触发更新。

检查以上几点,确保@Builder能正确响应状态变化并更新UI。

回到顶部