1. JS应用代码

  • hml
<div class="container" onclick="updateHeight" on:swipe="QuitApp">
    <div class="updateDiv" style="height: {{divHeight}}px;"></div>
</div>
  • js
export default {
    data: {
        heightIndex: 0,
        heightArr: [50, 100, 150],
        divHeight: 50,
    },
    updateHeight(){
        if(this.heightIndex == 2) {
            this.heightIndex = 0;
        } else {
            this.heightIndex++;
        }
        this.divHeight = this.heightArr[this.heightIndex];
    }
}
  • css
.container {
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.updateDiv {
  width: 6px;
  height: 50px;
  background-color: #5f7cb8;
  border-radius: 2px;
}

2. ace_lite监听数据变化入口 WatcherCallbackFunc

在WatcherCallbackFunc中主要是获取修改的属性和属性值将其传递给组件的UpdateView方法,UpdateView会更新并保存数据,处理成功后触发组件送显。

foundation/arkui/ace_engine_lite/frameworks/src/core/base/js_fwk_common.cpp

jerry_value_t WatcherCallbackFunc(const jerry_value_t func, const jerry_value_t context,
                                  const jerry_value_t *args, const jerry_length_t argsLength)
{
...
            bool updateResult = component->UpdateView(attrKeyId, value); // 更新视图及属性数据
            if (updateResult) {
                component->Invalidate(); // 触发组件送显
            }
...
}

3. ui_lite组件属性更新

送显需获取当前组件并记录尺寸和位置等信息,最终将需要更新的区域信息保存到rootView的invalidateRects_中。

foundation/arkui/ui_lite/frameworks/components/ui_view.cpp

void UIView::Invalidate()
{
    print_ms("0xc00 updateDiv UIView::Invalidate\n");
    UIView* view = this;
    while (view != nullptr) {
        if (view->transMap_ != nullptr && !view->GetTransformMap().IsInvalid() && view != this) {
            InvalidateRect(view->GetRect(), view); 
            return;
        }
        view = view->parent_;
    }
    InvalidateRect(GetRect());
}

# GetRect() 获取需更新区域的尺寸位置等信息

void UIView::InvalidateRect(const Rect& invalidatedArea, UIView* view)
{

        rootView->AddInvalidateRectWithLock(trunc, view); // 将要更新的视图信息保存到rootView的invalidateRects_中

}

4. RootView中处理渲染数据及触发送显

rootView中会周期的调用执行RootView::Render(),当前的周期是16ms执行一次,在Render()中会判断 invalidateRects_ 是否为空,当 invalidateRects_ 不为空时,会触发RenderManager::RenderRect(),并最终执行Flush将视图送显。

foundation/arkui/ui_lite/frameworks/components/root_view.cpp

void RootView::Render()
{
...
    if (!invalidateMap_.empty()) {
...
        RenderManager::RenderRect(flushRect, this); // 处理渲染所需的数据
...
        BaseGfxEngine::GetInstance()->Flush(flushRect); // 触发送显到屏幕
...
    }
}

RenderManager::RenderRect() 中主要通过调用rootView->DrawTop(topView, mask);将视图更新到最上层,DrawTop则会触发组件本身的OnDraw方法进行绘制数据处理。

void RenderManager::RenderRect(const Rect& rect, RootView* rootView)
{
...
    rootView->DrawTop(topView, mask); // 将视图更新到最上层
...
}
void RootView::DrawTop(UIView* view, const Rect& rect)
{
...
        curView->OnDraw(*dc_.bufferInfo, curViewRect); // 触发组件本身的绘制逻辑
...
}

div组件最终对应native实现为UIView,在UIView::OnDraw方法中,BaseGfxEngine::GetInstance()->DrawRect则是通过CPU更新需要送显的buffer数据。

foundation/arkui/ui_lite/frameworks/components/ui_view.cpp

void UIView::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
{
    uint8_t opa = GetMixOpaScale();
    BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetOrigRect(), invalidatedArea, *style_, opa); // 更新需要送显的buffer
}

以上执行完成后,执行BaseGfxEngine::GetInstance()->Flush送显到屏幕。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐