DirectSurface UIDirectSurface UI
开始使用
文档/核心概念

绘制与命中测试

绘制和命中测试共同决定用户看到什么,以及指针事件会落到哪个组件上。

绘制职责

绘制阶段只应该根据当前布局结果和组件状态输出绘制命令。它不应该改变会影响布局的数据。

绘制可以处理:

  • 背景。
  • 边框。
  • 文本。
  • 图标。
  • hover、selected、focused 状态。
  • 光标、选区和高亮。
  • 滚动条。

绘制顺序

一般顺序是:

  1. 背景。
  2. 内容。
  3. 前景装饰。
  4. 焦点框、选中框等状态层。

复杂组件需要明确自己的层级,例如表格通常先绘制单元格背景,再绘制文字,最后绘制网格线和焦点框。

何时只需要重绘

只影响视觉、不影响尺寸时,应触发重绘:

markNeedsPaint()

典型场景:

  • hover 状态变化。
  • selected 状态变化。
  • 焦点状态变化。
  • 光标闪烁。
  • 临时高亮。
  • 滚动条拖动反馈。

绘制边界与几何损伤

局部重绘以 RenderObject.paintBounds 为损伤边界。默认边界是节点的布局矩形;绘制阴影、光晕或其他越界内容的组件必须覆盖该边界。

位置变化需要同时清理旧位置并绘制新位置。自定义 RenderObject 应在更新 offset 前保存旧 paintBounds,然后调用 markNeedsPaintForGeometryChange(previousPaintBounds)。同一帧内的多次位置变化会累计为一个并集区域,不会遗漏中间绘制位置。

命中测试

命中测试用于确定指针位置下有哪些组件。事件派发系统会根据命中结果把 pointer、wheel 等事件交给对应组件。

组件通常需要先判断点是否在自身矩形内,再决定是否继续检查子组件。

滚动边界

滚动容器在处理 wheel 时要明确返回是否消费事件。如果内部还能滚动,应消费事件;如果已经到达边界,可以根据组件设计决定是否让外层继续处理。

列表、树、表格这类内部滚动组件应保持一致的滚动体验。

性能原则

  • paint 只绘制可视区域。
  • hit test 不应递归不可见子树。
  • 大数据组件应使用空间索引或可视范围,而不是每次全量扫描。
  • 频繁动画和光标闪烁应只触发必要区域重绘。
  • 几何移动应累计旧、新 paintBounds,不要只登记移动后的矩形。