【鸿蒙实战开发】基于Drawing的图形/文字绘制及双缓冲模拟实现刷新

场景描述

Native Drawing 模块提供了一系列的接口用于基本图形和字体的绘制。

Drawing绘制的内容无法直接在屏幕上显示,需要借用 XComponent 的能力支持,将绘制的内容通过Native Window送显。这里介绍如何使用Drawing绘制内容,然后通过NativeWindow贴图到XComponent的双缓冲实现。

双缓冲实现刷新:

  1. 在内存中创建一片内存区域,把将要绘制的图片预先绘制到内存中,在绘制显示的时候直接获取缓冲区的图片进行绘制。更具体一点来说:先通过Drawing方法将要绘制的所有的图形绘制到一个Bitmap上也就是先在内存空间完成,然后获取位图的像素地址、并将其拷贝到XComponent的NativeWindow地址。完成贴图,将图片显示在屏幕上。
  2. 启用双缓冲后,所有画图操作会首先呈现到内存缓冲而不是屏幕上的绘图图面。 所有画图操作完成后,内存缓冲会直接复制到与之关联的绘图图面。 由于屏幕上仅执行一个图形操作,因此与复杂画图操作相关的图像闪烁可得以消除。
  3. 很多图形的操作都很复杂需要大量的计算,很难访问一次显示缓冲区就能写入待显示的完整图形数据,通常需要多次访问显示缓冲区,每次访问时写入最新计算的图形数据。而这样造成的后果是一个需要复杂计算的图形,你看到的效果可能是一部分一部分地显示出来的,造成很大的闪烁不连贯。而使用双缓冲,可以使你先将计算的中间结果存放在另一个缓冲区中,待全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区。

方案描述

一.图形绘制:

1.使用Drawing进行图形绘制与显示时,需要使用Native Drawing模块的画布画笔绘制一个基本的2D图形;

2.将图形内容写入Native Window提供的图形Buffer,将Buffer提交到图形队列;

3.再利用XComponent将C++代码层与ArkTS层对接,实现在ArkTS层调用绘制和显示的逻辑,最终在应用上显示图形。

二.文本绘制:

Native Drawing模块关于文本绘制提供两类API接口

一类是具有定制排版能力的接口:如OH_Drawing_Typography,OH_Drawing_TypographyStyle,OH_Drawing_TextStyle等类型。支撑用户设置排版风格和文本风格,可调用OH_Drawing_TypographyHandlerAddText添加文本并调用OH_Drawing_TypographyLayout和OH_Drawing_TypographyPaint对文本进行排版和绘制。

另一类是不具有定制排版能力的接口:如OH_Drawing_Font,OH_Drawing_TextBlob,OH_Drawing_RunBuffer等类型。支撑具备自排版能力的用户将排版结果构造为OH_Drawing_TextBlob并调用OH_Drawing_CanvasDrawTextBlob绘制OH_Drawing_TextBlob描述的文本块。

场景实现

添加开发依赖

CMakeLists.txt中添加以下lib。

libace_napi.z.so
libace_ndk.z.so
libnative_window.so
libnative_drawing.so

使用XComponent构建绘制环境

1.使用XComponent组件

build() {
  Column() {
    Row() {
      XComponent({ id: 'xcomponentId', type: 'surface', libraryname: 'entry' })
        .onLoad((xComponentContext) => {
          this.xComponentContext = xComponentContext as XComponentContext;
        }).width('640px') // 64的倍数
    }.height('100%')
  }
}

2.在 Native C++层获取NativeXComponent与ts侧XComponent关联。此步骤需要在napi_init的过程中处理。创建一个PluginManger单例类,用于管理NativeXComponent。

class PluginManager {
  public:
  ~PluginManager();

  static PluginManager *GetInstance();

  void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent);
  SampleBitMap *GetRender(std::string &id);
  void Export(napi_env env, napi_value exports);
  private:

    std::unordered_map<std::string, OH_NativeXComponent *> nativeXComponentMap_;
  std::unordered_map<std::string, SampleBitMap *> pluginRenderMap_;
};
void PluginManager::Export(napi_env env, napi_value exports) {
  if ((env == nullptr) || (exports == nullptr)) {
    DRAWING_LOGE("Export: env or exports is null");
    return;
  }

  napi_value exportInstance = nullptr;
  if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
    DRAWING_LOGE("Export: napi_get_named_property fail");
    return;
  }

  OH_NativeXComponent *nativeXComponent = nullptr;
  if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
    DRAWING_LOGE("Export: napi_unwrap fail");
    return;
  }

  char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
  uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
  if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
    DRAWING_LOGE("Export: OH_NativeXComponent_GetXComponentId fail");
    return;
  }

  std::string id(idStr);
  auto context = Pl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值