Files
StellarX-kaifa/开发记录/功能变更/Feature-20260509-0011-布局API使用说明与旧接口覆盖规则.md

10 KiB
Raw Permalink Blame History

功能变更 ID: Feature-20260509-0011

适用场景:记录小到中等规模的功能、接口、行为、默认值或配置变化。 不适用场景:新增核心模块、重大模块重构、架构级设计,请使用“新增功能模块”模板。

基本信息

  • ID: Feature-20260509-0011
  • 标题: 布局 API 使用说明与旧接口覆盖规则
  • 状态:已验证
  • 类型:新增
  • 级别:L2 中等
  • 模块: Layout API / Control
  • 版本 / 分支: 当前工作区
  • 环境: Windows + EasyX
  • 负责人: Codex 协作修改

变更背景

  • 背景:
    • 当前布局系统内部已经以 LayoutSpec 为统一解算依据。
    • 旧接口 setLayoutMode(...) / setAnchor(...) 仍然保留,但只能表达有限的双锚点语义。
    • 新增公开布局 API 后,需要明确用户应如何设置轴向锚点、尺寸策略和固定尺寸位移策略。
  • 目标:
    • 说明新布局 API 的职责和使用方式。
    • 明确新旧接口混用时的覆盖规则。
    • 给出常见布局组合和 KEY2 迁移场景中的推荐写法。
  • 不做什么:[可选]
    • 不开放 LayoutCapability 的普通外部写入接口。
    • 不修改 Table 当前版本 Y Fixed 的能力边界。
    • 不处理 Tooltip 智能选位、Table 内部局部重绘、Dialog synthetic move 统一等后置项。

变更内容

  • 变更摘要:
    • 增加布局 API 使用说明文档。
    • 明确新接口与旧接口的覆盖关系。
    • 汇总常见布局模式的代码写法。
  • 新增项:[可选]
    • 新公开接口说明
    • 旧接口映射说明
    • 混用覆盖规则
    • 常见写法示例
    • 调试态日志说明
  • 修改项:[可选]
    • 无运行时代码修改,本文件只记录使用说明。
  • 删除 / 废弃项:[可选]
  • 受影响的文件 / 类 / 函数:
  • 对外 API / 属性变化:[可选]
    • setHorizontalLayoutSpec(...)
    • setVerticalLayoutSpec(...)
    • setHorizontalAnchors(...)
    • setVerticalAnchors(...)
    • setHorizontalSizePolicy(...)
    • setVerticalSizePolicy(...)
    • setHorizontalAlignPolicy(...)
    • setVerticalAlignPolicy(...)
    • getHorizontalLayoutSpec()
    • getVerticalLayoutSpec()

行为对照

  • 变更前:
    • 用户主要通过 setLayoutMode(...)setAnchor(...) 设置布局。
    • 固定尺寸 + 居中、固定尺寸 + 比例位移等组合无法通过旧接口清晰表达。
    • 旧双锚点在某些测试场景中会被迫承担 Stretch 语义,导致固定按钮和内容驱动标签在 resize 后错位。
  • 变更后:
    • 用户可按水平轴 / 垂直轴分别设置锚点集合、尺寸策略和固定尺寸位移策略。
    • 旧接口仍可用,但只作为兼容输入层。
    • 新旧接口混用时,最后调用的接口覆盖对应轴的布局规格。
  • 兼容性说明:兼容
  • 迁移说明:[可选]
    • 新代码建议优先使用新布局 API。
    • 旧代码可以继续使用 setAnchor(...),但复杂布局应逐步迁移到新接口。

验证与落地

API 总览

完整轴向规格接口

void setHorizontalLayoutSpec(const StellarX::AxisLayoutSpec& spec);
void setVerticalLayoutSpec(const StellarX::AxisLayoutSpec& spec);
  • 直接覆盖对应轴的完整布局规格。
  • 调用后自动切换到 StellarX::LayoutMode::AnchorToEdges
  • 适合调用方已经准备好完整 AxisLayoutSpec 的场景。

锚点集合接口

void setHorizontalAnchors(bool left, bool right);
void setVerticalAnchors(bool top, bool bottom);
  • 水平轴对应 left / right
  • 垂直轴对应 top / bottom
  • 只修改对应轴的锚点集合,不主动改变尺寸策略或位移策略。

尺寸策略接口

void setHorizontalSizePolicy(StellarX::AxisSizePolicy policy);
void setVerticalSizePolicy(StellarX::AxisSizePolicy policy);
  • Stretch:允许该轴尺寸随父容器变化。
  • FixedSize:该轴尺寸保持设计态尺寸。
  • 控件能力边界仍然生效。例如 Table 当前版本不允许 Y Stretch,即使用户设置垂直 Stretch,也会被能力边界降级。

固定尺寸位移策略接口

void setHorizontalAlignPolicy(StellarX::AxisAlignPolicy policy);
void setVerticalAlignPolicy(StellarX::AxisAlignPolicy policy);
  • 只在 FixedSize 语义下决定位置。
  • 不负责改变尺寸。
  • 常用值:
    • Start:保持起边关系,例如左固定、上固定。
    • End:保持终边关系,例如右固定、下固定。
    • Center:保持居中关系。
    • Proportional:保持设计态相对位置比例,适合固定尺寸控件在可变宽容器中按比例移动。

读取接口

StellarX::AxisLayoutSpec getHorizontalLayoutSpec() const;
StellarX::AxisLayoutSpec getVerticalLayoutSpec() const;
  • 返回当前生效的新模型轴向规格。
  • 不保证能完整逆映射回旧 anchor_1 / anchor_2 语义。

新旧接口覆盖规则

旧接口仍然保留

void setLayoutMode(StellarX::LayoutMode layoutMode);
void setAnchor(StellarX::Anchor anchor1, StellarX::Anchor anchor2);
  • 旧接口是兼容入口。
  • setAnchor(...) 内部会把旧双锚点映射到新的 layoutSpec.horizontallayoutSpec.vertical
  • 旧接口无法表达所有新模型状态,例如固定尺寸 + 比例位移、固定尺寸 + 居中等。

后调用者生效

规则:

  • 先调用 setAnchor(...),再调用新 API,则新 API 覆盖对应轴规格。
  • 先调用新 API,再调用 setAnchor(...),则旧接口重新覆盖水平轴和垂直轴规格。
  • 新 API 只覆盖自己负责的轴或字段。例如 setHorizontalSizePolicy(...) 只修改水平轴尺寸策略,不修改垂直轴。

示例:

button->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
button->setAnchor(StellarX::Anchor::Left, StellarX::Anchor::Right);

// 覆盖水平轴:改为固定尺寸 + 居中,不再沿用旧接口映射出的 Stretch。
button->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
button->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Center);

新 API 自动切换布局模式

所有新布局 setter 都会自动将 layoutMode 切换为 AnchorToEdges。 因此新代码通常不需要再额外写:

control->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);

常见布局写法

左固定

control->setHorizontalAnchors(true, false);
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Start);

右固定

control->setHorizontalAnchors(false, true);
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::End);

水平拉伸

control->setHorizontalAnchors(true, true);
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::Stretch);
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Start);

固定尺寸居中

control->setHorizontalAnchors(true, true);
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Center);

固定尺寸比例位移

control->setHorizontalAnchors(true, true);
control->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
control->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Proportional);

适用场景:

  • 一组固定尺寸按钮需要随着父容器变宽按比例展开。
  • KEY2 中每个 bit 单元就是该策略的典型使用方式。

KEY2 迁移要点

KEY2 原问题不是单纯参数错误,而是布局单元拆分不合理:

  • 位号 Label 是内容驱动尺寸。
  • 位按钮是固定尺寸。
  • 二者分别使用比例位移时,因为自身尺寸不同,resize 后会出现错位。

当前迁移方式:

  • 每一位创建一个小 Canvas 单元。
  • 单元内部固定放置位号 Label 与位按钮。
  • 单元自身使用 FixedSize + Proportional
  • 这样移动的是整个 bit 单元,而不是标签和按钮分别移动。

示意写法:

auto cell = std::make_unique<Canvas>(cellX, 0, 32, 50);
cell->setHorizontalAnchors(true, true);
cell->setHorizontalSizePolicy(StellarX::AxisSizePolicy::FixedSize);
cell->setHorizontalAlignPolicy(StellarX::AxisAlignPolicy::Proportional);

能力边界说明

布局 API 表达的是“调用方希望如何布局”,但控件能力边界仍然优先。

当前关键边界:

  • CanvasX / Y 均允许 Stretch。
  • TabControl:外层允许 Stretch,内部页签栏 / 页面区仍由自身管理。
  • Table:当前版本 X Stretch / Y Fixed,这是当前实现边界,不是永久产品结论。
  • TextBox:默认更适合 X Stretch / Y FixedSize
  • Label:默认固定或内容驱动刷新运行态尺寸,不建议做双轴 Stretch。
  • Dialog:只居中,不参与父级拉伸。

如果用户设置的策略超出控件能力边界,统一解算层会按现有降级规则处理,并保留必要日志。

调试态说明

resize / 最大化 / 还原过程中,如果开启大量 console 日志,可能出现一帧视觉延迟或短暂残影。 当前判断原因是日志系统同步写控制台且默认逐行 flush,导致主线程 resize 收口绘制被 I/O 拖慢。

处理建议:

  • 常规手测可关闭 console 日志。
  • 需要日志时可优先输出到文件。
  • 当前不作为布局或重绘 bug 处理,后续可在官网/API 文档中作为调试说明记录。