1. 输入接口对齐
将元素上的鼠标、键盘、滚轮回调改为事件对象。例如:
@Override
public boolean mousePressed(MousePressedEvent e) {
super.mousePressed(e);
// ...
}
旧参数 (mx, my, btn, dx, dy) 迁移为:
e.x(),e.y()e.button()e.dx(),e.dy()e.horizontal(),e.vertical()e.modifiers()
键盘事件直接读取 key(), scancode(), modifiers();IME 读取 text(), caretPosition(), blocks(), focusedBlock()。
2. 容器/子元素迁移
如果代码仍直接遍历 LayoutElement 的内部子元素,替换为 Element.children() 的公开访问。子元素的输入状态不再保存在 LayoutElement 中。
对应动作:
- 移除
LayoutElement.dispatchToTopmost(...)的直接调用; - 移除容器为某元素维护
pressOwner的字段或本地标记。
3. 浮层窗口迁移
原来的 OverlayNode 与 blocksMouse 已删除,迁移对应关系为:
OverlayTree.push(node)→OverlayTree.push(root, dismissOnOutsideClick)OverlayNode.blocking→ 已不存在,改用命中链路判断OverlayTree.onOutsideInteraction旁路判断 → 由InteractionManager.dismissOverlaysOutside统一向各层发送onOutsideInteraction()
如果旧代码手工清理浮层树结构,改为调用 OverlayTree.remove(root)。
4. 焦点与键盘迁移
检查旧的 FocusableElement 子类,确保键盘链路不再自行查找焦点:
keyPressed、charTyped、preeditUpdated继续返回 boolean;- 元素内不手写“当前元素是否为焦点”的分支,焦点判定由
InteractionManager的resolveKeyboardReceiver()完成; - 若旧逻辑依赖在字段里缓存接收者,改为在事件进入时按路由读取。
5. tick 迁移
将子元素 tick 递归合并到统一驱动:
- 在调用
UiTickDriver.onRenderFrame(manager)的位置,LayoutElement内部不再递归tick(); OverlayTree.tickAll()旧入口不存在,改由TickWalker.forEachElement(root, overlays, Element::tick)触发;InteractionManager.tick()旧入口同样不存在:它直接转发到TickWalker.forEachElement(root, overlays.tree(), Element::tick),按 20 TPS 运行;若与驱动器同时调用,每帧状态推进两次,即弹簧翻倍、动画速度加倍且不报错。Screen.tick()中改为调用uiTickDriver.onRenderFrame(interactionManager);需要其他节拍时直接调用TickWalker.forEachElement,该方法是 public static。- 任何“仅在父元素可见时递归调用子元素
tick()”的手写逻辑,现由TickWalker处理。
常见注意事项
HoverEvent不再区分mouseEntered/mouseMoved/mouseExited的事件类型;如果代码按事件名判定动作,则以调用方的分支为准。PreeditUpdatedEvent.toPlatformPreedit()是唯一直接适配 MCPreeditEvent的方法,不再自行构造平台PreeditEvent。LayoutElement只做布局与渲染,不再持有输入分发的中间状态。OverlayTree.Layer是扁平记录,不再按“节点嵌套父子链”的旧模型维护层级关系。InteractionManager的命中顺序以浮层树优先为准;根树仅作为浮层树的后备。