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 代码目录

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

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解析控件的实现:

构造函数-参数

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

 设置Theme

  1. void UIButton::SetupThemeStyles() 
  2.     Theme* theme = ThemeManager::GetInstance().GetCurrent(); 
  3.  
  4.     if (theme == nullptr) { 
  5.         buttonStyles_[RELEASED] = &(StyleDefault::GetButtonReleasedStyle()); 
  6.         buttonStyles_[PRESSED] = &(StyleDefault::GetButtonPressedStyle()); 
  7.         buttonStyles_[INACTIVE] = &(StyleDefault::GetButtonInactiveStyle()); 
  8.     } else { 
  9.         buttonStyles_[RELEASED] = &(theme->GetButtonStyle().released); 
  10.         buttonStyles_[PRESSED] = &(theme->GetButtonStyle().pressed); 
  11.         buttonStyles_[INACTIVE] = &(theme->GetButtonStyle().inactive); 
  12.     } 
  13.     style_ = buttonStyles_[RELEASED]; 

 绘制OnDraw

  1. void UIButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) 
  2.     OpacityType opa = GetMixOpaScale(); 
  3.     BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetOrigRect(), invalidatedArea, *buttonStyles_[state_], opa); 
  4.     DrawImg(gfxDstBuffer, invalidatedArea, opa); 

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

  1. void BaseGfxEngine::DrawRect(BufferInfo& dst, 
  2.                              const Rect& rect, 
  3.                              const Rect& dirtyRect, 
  4.                              const Style& style, 
  5.                              OpacityType opacity) 
  6.     DrawRect::Draw(dst, rect, dirtyRect, style, opacity); 

 第2个绘制图片->DrawImg

  1. void UIButton::DrawImg(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, OpacityType opaScale) 
  2.     const Image* image = GetCurImageSrc(); 
  3.     if (image == nullptr) { 
  4.         return
  5.     } 
  6.  
  7.     ImageHeader header = {0}; 
  8.     image->GetHeader(header); 
  9.     Rect coords; 
  10.     Rect viewRect = GetContentRect(); 
  11.     coords.SetLeft(viewRect.GetLeft() + GetImageX()); 
  12.     coords.SetTop(viewRect.GetTop() + GetImageY()); 
  13.     coords.SetWidth(header.width); 
  14.     coords.SetHeight(header.height); 
  15.  
  16.     Rect trunc(invalidatedArea); 
  17.     if (trunc.Intersect(trunc, viewRect)) { 
  18.         image->DrawImage(gfxDstBuffer, coords, trunc, *buttonStyles_[state_], opaScale); 
  19.     } 

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

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

事件处理

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

  1. void UIView::InvalidateRect(const Rect& invalidatedArea) 
  2.     if (!visible_) { 
  3.         if (needRedraw_) { 
  4.             needRedraw_ = false
  5.         } else { 
  6.             return
  7.         } 
  8.     } 
  9.  
  10.     Rect trunc(invalidatedArea); 
  11.     bool isIntersect = true
  12.     UIView* par = parent_; 
  13.     UIView* cur = this; 
  14.  
  15.     while (par != nullptr) { 
  16.         if (!par->visible_) { 
  17.             return
  18.         } 
  19.  
  20.         isIntersect = trunc.Intersect(par->GetContentRect(), trunc); 
  21.         if (!isIntersect) { 
  22.             break; 
  23.         } 
  24.  
  25.         cur = par; 
  26.         par = par->parent_; 
  27.     } 
  28.  
  29.     if (isIntersect && (cur->GetViewType() == UI_ROOT_VIEW)) { 
  30.         RootView* rootView = reinterpret_cast<RootView*>(cur); 
  31.         rootView->AddInvalidateRectWithLock(trunc, this); 
  32.     } 

在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 来源: 鸿蒙社区
相关推荐

2022-02-17 20:57:07

OpenHarmon操作系统鸿蒙

2022-01-06 16:17:58

鸿蒙HarmonyOS应用

2021-09-18 14:40:37

鸿蒙HarmonyOS应用

2021-11-08 15:04:47

鸿蒙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应用

2022-01-20 11:04:31

Linux DRMOpenHarmon鸿蒙

2023-06-28 15:00:02

开源鸿蒙输入系统架构

2021-09-17 14:38:58

鸿蒙HarmonyOS应用

2022-01-20 14:33:29

openharmonwayland协议鸿蒙

2022-02-14 14:47:11

SystemUIOpenHarmon鸿蒙

2022-03-18 16:07:04

Graphic子系统鸿蒙

2022-05-17 10:42:36

reboot源码解析

2013-01-06 13:06:02

点赞
收藏

51CTO技术栈公众号