HarmonyOS鸿蒙Next中在@Builder里调用@Component时,报错is not callable

HarmonyOS鸿蒙Next中在@Builder里调用@Component时,报错is not callable 想通过UIContext.getPromptAction().openCustomDialog()创建打开自定义弹窗,@builder无法满足要求,所以想在@builder里放一个@component,但是运行时崩溃,报错is not callable,晒代码:

Index.ets

// Index.ets
import { ComponentContent } from '@kit.ArkUI';
import { AIDialog } from '../components/AIDialog';
import { PromptActionClass } from '../components/PromptActionClass';

class Params {
  text: string = "";

  constructor(text: string) {
    this.text = text;
  }
}

[@Builder](/user/Builder)
function buildText() {
  AIDialog()
}

@Entry
[@Component](/user/Component)
struct Index {
  @State message: string = "hello";
  private ctx: UIContext = this.getUIContext();
  private contentNode: ComponentContent<Object> =
    new ComponentContent<Params>(this.ctx, wrapBuilder<[Params]>(buildText), new Params(this.message));

  aboutToAppear(): void {
    PromptActionClass.setContext(this.ctx);
    PromptActionClass.setContentNode(this.contentNode);
    PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } });
  }

  build() {
    Row() {
      Column() {
        Button("open dialog ")
          .margin({ top: 50 })
          .onClick(() => {
            PromptActionClass.openDialog();
          })
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}
import * as pag from '@tencent/libpag'
import { PAGView } from '@tencent/libpag'
import { common } from '@kit.AbilityKit';

[@Component](/user/Component)
export struct AIDialog {

  @State viewController: pag.PAGViewController = new pag.PAGViewController();
  private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;

  async aboutToAppear(): Promise<void> {
    let abnormalAnimationPath = this.context.resourceDir + "/bgAnimation.pag";
    // LoadFromPathAsync()可以加载网络或者本地文件
    let file = await pag.PAGFile.LoadFromPathAsync(abnormalAnimationPath)
    this.viewController.setComposition(file);
    this.viewController.setRepeatCount(0);
    this.viewController.play();
  }

  build() {
    Stack() {

      PAGView({
        controller: this.viewController
      })
        .width('100%')

      Column() {
        // 主要内容区域
        Row() {
          // 动画和文本的水平布局
          Row() {
            // 动画视图 (替代LottieAnimationView)
            Image($r('app.media.startIcon'))
              .width(36)
              .height(36)
              .margin({ right: 12 })

            // 监听状态文本
            Text('小舒正在听...')
              .fontSize(18)
              .fontColor('#F9F9F9')
              .textAlign(TextAlign.Center)
          }
          .alignItems(VerticalAlign.Center)
          .justifyContent(FlexAlign.Start)

          Blank()

          // 右侧按钮区域
          Row() {
            // 设置按钮
            Image($r('app.media.startIcon'))
              .width(20)
              .height(20)
              .margin({ right: 20 })
              .onClick(() => {
                // 设置按钮点击事件
              })

            // 关闭按钮
            Image($r('app.media.startIcon'))
              .width(20)
              .height(20)
              .onClick(() => {
                // 关闭按钮点击事件
              })
          }
          .alignItems(VerticalAlign.Center)
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .alignItems(VerticalAlign.Center)

        // 内容文本区域
        Text('试着说帮我开启一键入眠入眠帮我开入入眠帮我开眠帮我开入眠帮我开启眠帮我开启一键入眠帮我开启一键入眠')
          .fontSize(22)
          .fontColor('#F9F9F9')
          .maxLines(3)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .width('100%')
          .margin({ top: 20 })
          .lineHeight(28)

        // 操作说明文本
        Text('小舒正在为您开启一键入眠模式')
          .fontSize(22)
          .fontColor('#F9F9F9')
          .width('100%')
          .margin({ top: 20 })
          .lineHeight(28)

        // 底部间距
        Row()
          .height(16)
          .width('100%')
          .margin({ top: 20 })
      }
      .width('100%')
      .padding(2)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .constraintSize({minHeight:72})
    .linearGradient({
      direction: GradientDirection.Bottom,
      colors: [
        [0x66000000, 0.0],
        [0x99000000, 0.5],
        [0xCC000000, 1.0]
      ]
    })
    .borderRadius(12)
  }
}

错误截图:

PixPin_2025-07-10_11-37-25.png


更多关于HarmonyOS鸿蒙Next中在@Builder里调用@Component时,报错is not callable的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

这里加个参数就好了

@Builder
function buildText(params: Params) {
  AIDialog()
}

更多关于HarmonyOS鸿蒙Next中在@Builder里调用@Component时,报错is not callable的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


确实可以了,请问大佬为什么呢?

假如我是不传参数的弹窗呢?那就用不了了吗?

不传参数的话这里的Params 要换成void: new ComponentContent<void>(this.ctx, wrapBuilder<[void]>(buildText),

在HarmonyOS鸿蒙Next中,@Builder装饰的方法不能直接调用@Component组件。@Builder用于构建UI描述,而@Component是自定义组件,两者属于不同的概念层级。若要在@Builder中使用@Component,应将组件作为参数传递或通过build方法构建。错误提示"is not callable"表明直接调用方式不合法。正确做法是引用组件而非调用。

在HarmonyOS Next中,@Builder函数内直接调用@Component组件会导致"is not callable"错误。这是因为组件需要作为UI元素声明式使用,而不是函数式调用。

问题出在Index.ets中的buildText函数:

[@Builder](/user/Builder)
function buildText() {
  AIDialog()  // 错误用法
}

正确做法是使用组件声明语法:

[@Builder](/user/Builder)
function buildText() {
  // 正确用法
  Column() {
    AIDialog()
  }
}

或者更推荐的方式是直接在Builder中构建UI,而不是嵌套组件。对于自定义弹窗场景,建议:

  1. 将AIDialog的内容直接实现在Builder中
  2. 或者使用@BuilderParam来传递构建逻辑

根本原因是ArkUI的组件系统采用声明式语法,组件必须作为子元素嵌套在容器组件内,不能直接函数式调用。

回到顶部