场景描述
Native Drawing 模块提供了一系列的接口用于基本图形和字体的绘制。
Drawing绘制的内容无法直接在屏幕上显示,需要借用 XComponent 的能力支持,将绘制的内容通过Native Window送显。这里介绍如何使用Drawing绘制内容,然后通过NativeWindow贴图到XComponent的双缓冲实现。
双缓冲实现刷新:
- 在内存中创建一片内存区域,把将要绘制的图片预先绘制到内存中,在绘制显示的时候直接获取缓冲区的图片进行绘制。更具体一点来说:先通过Drawing方法将要绘制的所有的图形绘制到一个Bitmap上也就是先在内存空间完成,然后获取位图的像素地址、并将其拷贝到XComponent的NativeWindow地址。完成贴图,将图片显示在屏幕上。
- 启用双缓冲后,所有画图操作会首先呈现到内存缓冲而不是屏幕上的绘图图面。 所有画图操作完成后,内存缓冲会直接复制到与之关联的绘图图面。 由于屏幕上仅执行一个图形操作,因此与复杂画图操作相关的图像闪烁可得以消除。
- 很多图形的操作都很复杂需要大量的计算,很难访问一次显示缓冲区就能写入待显示的完整图形数据,通常需要多次访问显示缓冲区,每次访问时写入最新计算的图形数据。而这样造成的后果是一个需要复杂计算的图形,你看到的效果可能是一部分一部分地显示出来的,造成很大的闪烁不连贯。而使用双缓冲,可以使你先将计算的中间结果存放在另一个缓冲区中,待全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区。
方案描述
一.图形绘制:
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