HarmonyOS鸿蒙Next中Grid卡片列表页面通过NodeContainer渲染,长按拖拽时onPreDrag自定义缩率图导致布局错乱和文本消失问题

HarmonyOS鸿蒙Next中Grid卡片列表页面通过NodeContainer渲染,长按拖拽时onPreDrag自定义缩率图导致布局错乱和文本消失问题 自定义节点卡片+自定义节点拖拽缩率图一定会出现,下面是详细代码

import {  NodeController, BuilderNode, Size, FrameNode ,UIContext } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';

@Builder
function buttonBuilder(params: GridItemData) {
  Column() {
    // ID显示
    Text(`ID: ${params.id}`)
      .fontSize(16)
      .fontColor(Color.White)
      .fontWeight(FontWeight.Medium)

    // 文本内容
    Text(params.text)
      .fontSize(14)
      .fontColor(Color.White)
      .margin({ top: 5 })
      .maxLines(1)
      .textOverflow({ overflow: TextOverflow.Ellipsis })
  }.justifyContent(FlexAlign.Center)
}

class MyNodeController extends NodeController {
  private buttonNode: BuilderNode<[GridItemData]> | null = null;
  private wrapBuilder: WrappedBuilder<[GridItemData]> = wrapBuilder(buttonBuilder);
  private dataItem: GridItemData | null = null

  constructor(data: GridItemData) {
    super()
    this.dataItem = data
  }

  makeNode(uiContext: UIContext): FrameNode {
    if (this.buttonNode == null) {
      this.buttonNode = new BuilderNode(uiContext);
      this.buttonNode.build(this.wrapBuilder, this.dataItem)
    }
    return this.buttonNode!.getFrameNode()!;
  }
}


@ObservedV2
class GridItemData {
  id: number;
  @Trace text: string;
  constructor(id: number, text: string) {
    this.id = id
    this.text = text
  }
}

// 入口组件
@ComponentV2
export struct GridPage {
  // 使用@Local装饰器定义响应式数据
  @Local itemList: GridItemData[] = [
    new GridItemData(1, '项目一'),
    new GridItemData(2, '项目二'),
    new GridItemData(3, '项目三'),
    new GridItemData(4, '项目四'),
    new GridItemData(5, '项目五'),
    new GridItemData(6, '项目六'),
    new GridItemData(7, '项目七'),
    new GridItemData(8, '项目八')
  ];


  build() {
    Grid() {
      // 使用Repeat进行循环渲染
      Repeat<GridItemData>(this.itemList)
        .each((item: RepeatItem<GridItemData>) => {
          GridItem() {
            GridItemContent({
              gridItemData: item.item
            })
          }
          .borderRadius(12)
        })
        .key((item: GridItemData) => item.id.toString())
    }
    .columnsTemplate('1fr 1fr') // 2列等分布局
    .rowsGap(12)
    .columnsGap(12)
    .padding(10)
  }
}

@ComponentV2
struct GridItemContent {
  @Param @Require gridItemData: GridItemData
  @Local pixelMap: image.PixelMap | undefined = undefined;

  private myNodeController: MyNodeController = new MyNodeController(this.gridItemData);

  // 截图缩率图
  @Builder
  pixelMapBuilder() {
    Column() {
      RelativeContainer() {
        NodeContainer(this.myNodeController)
        Text('自定义缩率图').alignRules({
          end: { anchor: '__container__', align: HorizontalAlign.End },
          top: { anchor: '__container__', align: VerticalAlign.Top }
        })
      }
    }
    .height(100)
    .width(180)
    .backgroundColor(Color.Red)
  }

  private getComponentSnapshot(): void {
    this.getUIContext().getComponentSnapshot().createFromBuilder(() => {
      this.pixelMapBuilder()
    }, (error: Error, pixmap: image.PixelMap) => {
      if (error) {
        return;
      }
      this.pixelMap = pixmap;
    })
  }

  // 准备阶段截图
  private PreDragChange(preDragStatus: PreDragStatus): void {
    if (preDragStatus == PreDragStatus.ACTION_DETECTING_STATUS) {
      this.getComponentSnapshot();
    }
  }

  build() {
    Stack() {
      // 自定义节点渲染
      RelativeContainer() {
        if (this.myNodeController) {
          NodeContainer(this.myNodeController)
        }
      }
    }
    .width('100%')
    .height(100)
    .backgroundColor(0x007DFF)
    .onPreDrag((status: PreDragStatus)=>{
      this.PreDragChange(status);
    })
    // 拖拽开始,返回自定义缩率图
    .onDragStart((event?: DragEvent, extraParams?: string) => {
      let dragItemInfo: DragItemInfo = {
        pixelMap: this.pixelMap,
        builder: () => {
          this.pixelMapBuilder()
        },
      };
      return dragItemInfo;
    })
  }
}

更多关于HarmonyOS鸿蒙Next中Grid卡片列表页面通过NodeContainer渲染,长按拖拽时onPreDrag自定义缩率图导致布局错乱和文本消失问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,Grid卡片通过NodeContainer渲染时,onPreDrag自定义缩略图可能导致布局错乱和文本消失。这通常是因为自定义缩略图的尺寸或布局属性与原始节点不匹配,或拖拽过程中节点状态管理异常。建议检查自定义缩略图的布局约束,确保其与Grid项布局一致,并验证拖拽事件中节点的属性同步。

更多关于HarmonyOS鸿蒙Next中Grid卡片列表页面通过NodeContainer渲染,长按拖拽时onPreDrag自定义缩率图导致布局错乱和文本消失问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


问题出在getComponentSnapshot的异步调用与onDragStart的同步返回之间存在时序冲突。当onPreDrag触发时,createFromBuilder是异步操作,但onDragStart立即需要pixelMap,此时截图可能尚未完成,导致返回undefined或旧数据。

解决方案是使用@State装饰器确保pixelMap更新触发UI重建,并在onDragStart中返回有效的缩略图:

@ComponentV2
struct GridItemContent {
  @Param @Require gridItemData: GridItemData
  @State @Trace pixelMap: image.PixelMap | undefined = undefined; // 改为@State

  // 截图方法保持不变
  private getComponentSnapshot(): void {
    this.getUIContext().getComponentSnapshot().createFromBuilder(() => {
      this.pixelMapBuilder()
    }, (error: Error, pixmap: image.PixelMap) => {
      if (error) {
        return;
      }
      this.pixelMap = pixmap; // @State会自动触发更新
    })
  }

  // onDragStart中确保返回有效数据
  .onDragStart((event?: DragEvent, extraParams?: string) => {
    let dragItemInfo: DragItemInfo = {
      pixelMap: this.pixelMap,
      builder: () => {
        this.pixelMapBuilder()
      },
    };
    return dragItemInfo;
  })
}

关键修改:

  1. pixelMap改为@State @Trace装饰,确保数据更新时UI能响应
  2. onDragStart直接返回当前pixelMap,由ArkUI框架处理响应式更新

这样能保证拖拽时始终返回最新的截图数据,避免布局错乱和文本消失。

回到顶部