OpenHarmony 源码解析之图形子系统(UI)

系统
本文基于OpenHarmony 3.0为基础,讲解Graphic子系统的UI。 图形UI组件实现了一套系统级的图形引擎,该组件为应用开发提供UIKit接口,包括了动画、布局、图形转换、事件处理,以及丰富的UI组件。

[[441037]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

1 简介

本文基于OpenHarmony 3.0为基础,讲解Graphic子系统的UI。 图形UI组件实现了一套系统级的图形引擎,该组件为应用开发提供UIKit接口,包括了动画、布局、图形转换、事件处理,以及丰富的UI组件。组件内部直接调用HAL接口,或者使用WMS(Window Manager Service)提供的客户端与硬件交互,以完成事件响应、图像绘制等操作。目前只看到在L1有使用。

1.1 图形子系统相关

  • 《OpenHarmony 源码解析之图形子系统 (一)》
  • 《OpenHarmony 源码解析之图形子系统(UI)》

1.2 OpenHarmony 架构图

#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区

1.3 图形子系统架构图

#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区

2 基础知识

2.1 代码目录

/foundation/graphic/ui 
├── frameworks                  # 框架代码 
│   ├── animator                # 动画模块 
│   ├── common                  # 公共模块 
│   ├── components              # 组件 
│   ├── core                    # ui主流程(渲染、任务管理等) 
│   ├── default_resource 
│   ├── dfx                     # 维测功能 
│   ├── dock                    # 驱动适配层 
│   │   └── ohos                # ohos平台适配 
│   ├── draw                    # 绘制逻辑 
│   ├── engines                 # 绘制引擎 
│   │   ├── dfb 
│   │   ├── general 
│   │   ├── gpu_vglite 
│   │   └── software_zlite 
│   ├── events                  # 事件 
│   ├── font                    # 字体 
│   ├── imgdecode               # 图片管理 
│   ├── layout                  # 页面布局 
│   ├── themes                  # 主题管理 
│   ├── window                  # 窗口管理适配层 
│   └── window_manager 
│       └── dfb 
├── interfaces                  # 接口 
│   ├── innerkits               # 模块间接口 
│   │   └── xxx                 # 子模块的接口 
│   └── kits                    # 对外接口 
│       └── xxx                 # 子模块的接口 
├── test                        # 测试代码 
│   ├── framework 
│   │   ├── include             # 测试框架头文件 
│   │   └── src                 # 测试框架源码 
│   ├── uitest                  # 显示效果测试(可执行程序在foundation/graphic/wms/test:sample_ui) 
│   │   └── test_xxx            # 具体UI组件效果测试 
│   └── unittest                # 单元测试 
│       └── xxx                 # 具体UI组件单元测试 
└── tools                       # 测试和模拟器工具(模拟器工程、资源文件) 
    └── qt                      # QT工程 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

2.2 图形组件一览

#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区

3 实践

3.1 UI控件效果

具体UI控件效果可以通过QT Creator运行QT工程,效果如下:

#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区
#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区

所有UI控件在工程都可以找到效果,通过查看工程代码可以了解到各控件的使用方式以及参数详情。

3.2 示例

下面我们举例UIButton解析控件的实现:

构造函数-参数

UIButton::UIButton() 
    : defaultImgSrc_(nullptr), 
      triggeredImgSrc_(nullptr), 
      currentImgSrc_(ButtonImageSrc::BTN_IMAGE_DEFAULT), 
      imgX_(0), 
      imgY_(0), 
      contentWidth_(0), 
      contentHeight_(0), 
      state_(RELEASED), 
      styleState_(RELEASED), 
#if DEFAULT_ANIMATION 
      enableAnimation_(true), 
      animator_(*this), 
#endif 
      buttonStyleAllocFlag_(false
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

 设置Theme

void UIButton::SetupThemeStyles() 

    Theme* theme = ThemeManager::GetInstance().GetCurrent(); 
 
    if (theme == nullptr) { 
        buttonStyles_[RELEASED] = &(StyleDefault::GetButtonReleasedStyle()); 
        buttonStyles_[PRESSED] = &(StyleDefault::GetButtonPressedStyle()); 
        buttonStyles_[INACTIVE] = &(StyleDefault::GetButtonInactiveStyle()); 
    } else { 
        buttonStyles_[RELEASED] = &(theme->GetButtonStyle().released); 
        buttonStyles_[PRESSED] = &(theme->GetButtonStyle().pressed); 
        buttonStyles_[INACTIVE] = &(theme->GetButtonStyle().inactive); 
    } 
    style_ = buttonStyles_[RELEASED]; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

 绘制OnDraw

void UIButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) 

    OpacityType opa = GetMixOpaScale(); 
    BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetOrigRect(), invalidatedArea, *buttonStyles_[state_], opa); 
    DrawImg(gfxDstBuffer, invalidatedArea, opa); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

 可以看到需要绘制2个,第一个通过绘制引擎绘制点->DrawRect,

void BaseGfxEngine::DrawRect(BufferInfo& dst, 
                             const Rect& rect, 
                             const Rect& dirtyRect, 
                             const Style& style, 
                             OpacityType opacity) 

    DrawRect::Draw(dst, rect, dirtyRect, style, opacity); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

 第2个绘制图片->DrawImg

void UIButton::DrawImg(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, OpacityType opaScale) 

    const Image* image = GetCurImageSrc(); 
    if (image == nullptr) { 
        return
    } 
 
    ImageHeader header = {0}; 
    image->GetHeader(header); 
    Rect coords; 
    Rect viewRect = GetContentRect(); 
    coords.SetLeft(viewRect.GetLeft() + GetImageX()); 
    coords.SetTop(viewRect.GetTop() + GetImageY()); 
    coords.SetWidth(header.width); 
    coords.SetHeight(header.height); 
 
    Rect trunc(invalidatedArea); 
    if (trunc.Intersect(trunc, viewRect)) { 
        image->DrawImage(gfxDstBuffer, coords, trunc, *buttonStyles_[state_], opaScale); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

 可以发现最终还是调用draw目录下通过绘制点、线、图片等等来进行绘制:

#星光计划2.0# OpenHarmony 源码解析之图形子系统(UI)-鸿蒙HarmonyOS技术社区

事件处理

UIButton只重写了OnPressEvent,OnReleaseEvent和OnCancelEvent,增加了动画,具体实现还是在基类UIView,主要使用的函数:

void UIView::InvalidateRect(const Rect& invalidatedArea) 

    if (!visible_) { 
        if (needRedraw_) { 
            needRedraw_ = false
        } else { 
            return
        } 
    } 
 
    Rect trunc(invalidatedArea); 
    bool isIntersect = true
    UIView* par = parent_; 
    UIView* cur = this; 
 
    while (par != nullptr) { 
        if (!par->visible_) { 
            return
        } 
 
        isIntersect = trunc.Intersect(par->GetContentRect(), trunc); 
        if (!isIntersect) { 
            break; 
        } 
 
        cur = par; 
        par = par->parent_; 
    } 
 
    if (isIntersect && (cur->GetViewType() == UI_ROOT_VIEW)) { 
        RootView* rootView = reinterpret_cast<RootView*>(cur); 
        rootView->AddInvalidateRectWithLock(trunc, this); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

在UIView里面可以发现还有很多事件比如:OnLongPressEvent,我们可以重写来自定义效果。

UIView重要函数说明

(1) OnPreDraw——准备绘制

(2) OnDraw——绘制动作

(3) OnPostDraw——能在UI线程绘制

(4) Invalidate——请求重新绘制,有需要更新界面就可以调用此函数重新绘制

(5) Scale——缩放事件

(6) Translate——移动事件

(7) OnPressEvent等——触摸事件

还有很多常用的函数,有兴趣的同学可以自行查阅。

4 总结

到这我们对UI控件的一个使用和效果都有了解,底层实现流程也熟悉。不管是直接绘制还是通过绘制引擎绘制,最终还是调用draw目录下的绘制函数。自定义控件我们可以继承现有控件,扩展实现效果,还可以直接继承基类UIView。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-11-08 15:04:47

鸿蒙HarmonyOS应用

2022-02-17 20:57:07

OpenHarmon操作系统鸿蒙

2022-01-06 16:17:58

鸿蒙HarmonyOS应用

2021-09-18 14:40:37

鸿蒙HarmonyOS应用

2023-04-12 15:31:11

系统服务管理鸿蒙

2022-01-10 15:30:11

鸿蒙HarmonyOS应用

2022-05-10 11:17:27

电话子系统数据服务模块

2021-11-18 10:28:03

鸿蒙HarmonyOS应用

2022-05-24 15:46:51

Wi-FiSTA模式

2021-09-13 15:15:18

鸿蒙HarmonyOS应用

2023-04-06 09:14:11

多模输入子系统鸿蒙

2022-01-13 10:11:59

鸿蒙HarmonyOS应用

2023-06-28 15:00:02

开源鸿蒙输入系统架构

2022-01-20 11:04:31

Linux DRMOpenHarmon鸿蒙

2021-09-17 14:38:58

鸿蒙HarmonyOS应用

2022-01-20 14:33:29

openharmonwayland协议鸿蒙

2022-03-18 16:07:04

Graphic子系统鸿蒙

2022-02-14 14:47:11

SystemUIOpenHarmon鸿蒙

2022-05-17 10:42:36

reboot源码解析

2013-01-06 13:06:02

点赞
收藏

51CTO技术栈公众号