请求自绘制内容绘制帧率
===========

对于基于[XComponent](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/napi-xcomponent-guidelines)进行Native开发的业务，可以请求独立的绘制帧率进行内容开发，如游戏、自绘制UI框架对接等场景。

#### 接口说明

| 函数名称 | 说明 |
| :-- | :-- |
| OH\_NativeXComponent\_SetExpectedFrameRateRange (OH\_NativeXComponent \*component, OH\_NativeXComponent\_ExpectedRateRange \*range) | 设置帧期望的帧率范围。 |
| OH\_NativeXComponent\_RegisterOnFrameCallback (OH\_NativeXComponent \*component, OH\_NativeXComponent\_OnFrameCallback \*callback) | 设置每帧回调函数，同时启动每帧回调。 |
| OH\_NativeXComponent\_UnregisterOnFrameCallback (OH\_NativeXComponent \*component) | 取消注册的每帧回调函数，同时停止调用回调函数。 |

详细的接口说明请参考[OH\_NativeXComponent Native XComponent](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-oh-nativexcomponent-native-xcomponent)。

#### 开发步骤

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/af/v3/arGFAUNCQiWguJbYxi4ZvA/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260709T132544Z&HW-CC-Expire=86400&HW-CC-Sign=2EF7A64E7C17A0D1C2981EA430AB855723A168CEFBA328811C2A9A008F62B25C)

本范例是通过Drawing在Native侧实现图形的绘制，并将其呈现在NativeWindow上，具体可参考[使用Drawing实现图形绘制与显示](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/graphic-drawing-overview)。

1.  添加开发依赖。
    
    CMakeLists.txt中添加以下lib。
    
    target\_link\_libraries(entry PUBLIC libace\_napi.z.so libnative\_drawing.so libnative\_window.so libace\_ndk.z.so)
    
    导入依赖的相关头文件。
    
    #include <ace/xcomponent/native\_interface\_xcomponent.h>
    #include <arpa/nameser.h>
    #include <bits/alltypes.h>
    #include <native\_window/external\_window.h>
    #include <native\_drawing/drawing\_bitmap.h>
    #include <native\_drawing/drawing\_color.h>
    #include <native\_drawing/drawing\_canvas.h>
    #include <native\_drawing/drawing\_pen.h>
    #include <native\_drawing/drawing\_brush.h>
    #include <native\_drawing/drawing\_path.h>
    #include <cstdint>
    #include <map>
    #include <sys/mman.h>
    #include <string>
    #include "napi/native\_api.h"
    
    #include <native\_drawing/drawing\_text\_typography.h>
    
2.  定义ArkTS接口文件XComponentContext.ts，用来对接Native层。
    
    export default interface XComponentContext {
      register(): void;
    
      unregister(): void;
    };
    
3.  定义演示页面，包含两个XComponent组件。
    
    import XComponentContext from '../interface/XComponentContext';
    // ...
    
    @Entry
    @Component
    struct Index {
      private xComponentContext1: XComponentContext | undefined = undefined;
      private xComponentContext2: XComponentContext | undefined = undefined;
    
      build() {
        Column() {
          Row() {
            // ...
    
            XComponent({
              id: 'xcomponentId\_30',
              type: XComponentType.SURFACE,
              libraryname: 'entry'
            })
              .onLoad((xComponentContext) => {
                this.xComponentContext1 = xComponentContext as XComponentContext;
              }).width('640px')
              // ...
          }.height('40%')
    
          Row() {
            // ...
    
            XComponent({
              id: 'xcomponentId\_120',
              type: XComponentType.SURFACE,
              libraryname: 'entry'
            })
              .onLoad((xComponentContext) => {
                this.xComponentContext2 = xComponentContext as XComponentContext;
              }).width('640px')
              // ...
          }.height('40%')
    
          // ...
        }
      }
    }
    
4.  Native层配置帧率和注册回调函数。
    
    static void TestCallback(OH\_NativeXComponent \*component, uint64\_t timestamp, uint64\_t targetTimestamp)
    {
        // ...
        
        int32\_t xSize = OH\_NativeXComponent\_GetXComponentSize(component, nativeWindow, &width, &height);
        if ((xSize == OH\_NATIVEXCOMPONENT\_RESULT\_SUCCESS) && (render != nullptr)) {
            render->Prepare();
            render->Create();
            if (id == "xcomponentId\_30") {
                int offset = 16;
                render->ConstructPath(offset, offset, render->defaultOffsetY);
            }
            if (id == "xcomponentId\_120") {
                int offset = 4;
                render->ConstructPath(offset, offset, render->defaultOffsetY);
            }
            // ...
        }
    }
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/ee/v3/lyAITyL-QtWFeaAdpwmkJg/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260709T132544Z&HW-CC-Expire=86400&HW-CC-Sign=D5FD343932E15547A201D609AB04BCB23A63DFE10A139222AC81B47051127395)
    
    *   Callback回调函数运行于UI主线程，故涉及UI线程的耗时操作不应运行于回调函数中，以免影响性能。
    *   实例在调用OH\_NativeXComponent\_RegisterOnFrameCallback后，在不需要进行帧率控制时，应进行OH\_NativeXComponent\_UnregisterOnFrameCallback操作，避免内存泄漏及性能功耗影响。
    *   API version 18之前，应用调用OH\_NativeXComponent\_RegisterOnFrameCallback接口设置回调函数，如果没有取消注册，在XComponent实例存在期间，能一直收到期望回调。
    *   从API version 18开始，应用调用OH\_NativeXComponent\_RegisterOnFrameCallback接口设置回调函数，如果没有取消注册，只在XComponent上树期间，能收到期望回调。
    
    void SampleXComponent::RegisterOnFrameCallback(OH\_NativeXComponent \*nativeXComponent)
    {
        // ...
        OH\_NativeXComponent\_RegisterOnFrameCallback(nativeXComponent, TestCallback);
    }
    
    napi\_value SampleXComponent::NapiRegister(napi\_env env, napi\_callback\_info info)
    {
        // ...
            render->RegisterOnFrameCallback(nativeXComponent);
            // ...
    }
    
    napi\_value SampleXComponent::NapiUnregister(napi\_env env, napi\_callback\_info info)
    {
        // ...
            OH\_NativeXComponent\_UnregisterOnFrameCallback(nativeXComponent);
            // ...
    }
    
5.  TS层注册和取消注册每帧回调。
    
    Row() {
      Button('Start')
        .id('Start')
        .fontSize(14)
        .fontWeight(500)
        .margin({ bottom: 20, right: 6, left: 6 })
        .onClick(() => {
          if (this.xComponentContext1) {
            this.xComponentContext1.register();
          }
          if (this.xComponentContext2) {
            this.xComponentContext2.register();
          }
        })
        .width('30%')
        .height(40)
        .shadow(ShadowStyle.OUTER\_DEFAULT\_LG)
    
      Button('Stop')
        .id('Stop')
        .fontSize(14)
        .fontWeight(500)
        .margin({ bottom: 20, left: 6 })
        .onClick(() => {
          if (this.xComponentContext1) {
            this.xComponentContext1.unregister();
          }
          if (this.xComponentContext2) {
            this.xComponentContext2.unregister();
          }
        })
        .width('30%')
        .height(40)
        .shadow(ShadowStyle.OUTER\_DEFAULT\_LG)
    
      // ...
    }