范围:源码目录定位与类继承关系。
前置:无。
项目定位
FluentUI 是一个客户端 Fabric Minecraft 模组,提供了一套完整的 UI 框架,用于构建丰富的 Minecraft GUI 界面。它不是一个独立的库,而是扩展了 Minecraft 的 Screen 类并依赖 Fabric API,因此所有公开入口都位于模组初始化与具体 Screen 子类上。
框架有五个核心特性:
- 自渲染:所有 UI 元素通过
GuiGraphicsExtractor自行绘制,绕过 Minecraft 原生的 widget 系统,因此每个Element自行绘制自身的像素。 - 单一事件入口:所有鼠标、键盘、焦点与覆盖层路由都经过 InteractionManager,Screen 只做转发。
- 惰性布局:元素仅在
dirty标志被置位时才重新测量与排列,机制详见 布局系统。 - 覆盖层树:工具提示、上下文菜单、对话框等浮动元素组织为一棵多根森林,推送与渲染语义见 覆盖层系统。
- 链式 API:每个 setter 通过自界定泛型返回具体的子类型,支持流畅的构建器写法;泛型取舍的背景记录在 设计决策。
源码结构
目录树标注每个子系统的位置与关键文件的行数;行数取自当前源码,改动后需同步更新。
FluentUI/
├── build.gradle # Fabric Loom,使用分离的源集
├── gradle.properties # MC 26.2, Java 25, mod_version 26.7.0
├── src/
│ ├── main/java/xianfish/fluentui/
│ │ └── FluentUI.java # 公共入口 (ModInitializer)
│ └── client/java/xianfish/fluentui/client/
│ ├── FluentScreen.java # 抽象基类 Screen
│ ├── FluentUIClient.java # 客户端入口 (ClientModInitializer)
│ └── ui/
│ ├── element/
│ │ ├── Element.java # 根基类 (186 行)
│ │ ├── LayoutElement.java # 容器基类 (62 行)
│ │ ├── TooltippingElement.java
│ │ ├── FocusableElement.java
│ │ ├── Focusable.java
│ │ ├── KeyboardReceiver.java
│ │ ├── Margin.java
│ │ └── layout/
│ │ ├── StackPanel.java # 线性堆叠 (225 行)
│ │ ├── Canvas.java # 自由定位 (68 行)
│ │ ├── EntryRow.java # 标签+控件行 (41 行)
│ │ ├── Orientation.java
│ │ ├── StackDirection.java
│ │ ├── OverflowMode.java
│ │ └── Anchor.java
│ ├── interaction/
│ │ ├── InteractionManager.java # 中央事件路由器
│ │ └── Hit.java # 静态碰撞检测 (73 行)
│ ├── overlay/
│ │ ├── OverlayManager.java # 覆盖层树的持有方 (42 行)
│ │ └── OverlayTree.java # 多根森林 (136 行)
│ ├── component/ # 15 个具体组件(清单见下)
│ ├── animation/
│ │ ├── Animator.java
│ │ └── Easing.java
│ └── util/
│ ├── Colors.java
│ └── UIRenderUtil.java
ui/component/ 下共有 15 个组件类,是贡献者最常改动的叶子类:Button、Toggle、SelectBox、Slider、Stepper、TextBox、AutoCompleteBox、SelectDropdown、ListView、ItemList、ItemView、Tooltip、ContextMenu、MessageFlyout、ProgressBar。
类层次结构
元素体系由 Element 分出三条支线:布局容器、可悬浮元素、可聚焦元素。全模块的继承关系以下图为准:元素系统 展开元素侧的细节,但与此图一致。
Element<T> # 根基类
├── LayoutElement<T> # 添加子元素 + 滚动
│ ├── StackPanel # 线性布局 (H/V)
│ ├── Canvas # 自由定位 + 锚点
│ └── EntryRow # 左标签 + 右控件
├── TooltippingElement<T> # 添加工具提示支持
│ ├── FocusableElement<T> # 添加焦点 + 键盘输入(其本身也是组件基类)
│ │ ├── TextBox # 文本输入
│ │ ├── AutoCompleteBox # 自动完成输入
│ │ └── Stepper # 数字步进器
│ ├── Toggle # 开关
│ ├── Slider # 滑条
│ ├── SelectBox # 选择框
│ ├── ListView # 列表视图
│ │ └── ItemList # 可编辑列表(继承自 ListView)
│ ├── ItemView # 项视图
│ └── SelectDropdown # 下拉选择(内部 DropPanel 才是覆盖层)
└── 直接继承 Element 的组件
├── Button # 按钮
├── Tooltip # 悬停工具提示
├── ProgressBar # 进度条
├── ContextMenu # 右键菜单
└── MessageFlyout # Toast 通知
SelectDropdown 与 Tooltip 不属于 TooltippingElement 分支。 SelectDropdown 只是 TooltippingElement,真正带覆盖层语义的是其内部的 DropPanel 私有类;Tooltip 直接继承 Element,由其他元素依据 TooltippingElement 的悬浮逻辑推送。同理,AutoCompleteBox 内部的 DropdownOverlay 也是私有 Element 子类,而非顶层组件;内部面板类不进组件清单,也不进上图的分支。
不变量
- 继承层次是对外契约:上图中每个类的父类位置决定了它能用的能力(悬浮、焦点、覆盖层生命周期、子元素布局),改动任何
extends都等于改动能力集合,必须同步概述中的类层次图、ElementSystem 的复述以及涉及组件的文档。 - 组件清单恒为 15 个:新增或删除
ui/component/下的顶层组件类时,源码结构中的清单必须同步;内部私有面板类(如 DropPanel、DropdownOverlay)永远不计入。 - 行数表以源码为准:InteractionManager 465、Hit 73、OverlayManager 42、OverlayTree 136、Element 186、LayoutElement 62、StackPanel 225、Canvas 68、EntryRow 41;改动这些文件后应同步更新对应行数,避免文档与源码不一致。
- 版本号以
gradle.properties为准:当前mod_version=26.7.0。
连带影响
- 调整某个组件的父类(例如让 Tooltip 改为继承 TooltippingElement),会同时改变它的悬浮能力、覆盖层推送方式与命中分发路径,波及 元素系统 的字段说明和该组件的开发文档。
ui/element/layout/下新增一种容器时,需要在源码结构、类层次图、布局系统 的容器小节三处同步。- 修改
Element的核心字段或layout()语义,会波及全部 15 个组件与三条渲染/输入流水线,见 元素系统 与 根树与层级系统。 - 修改
InteractionManager的路由规则(全仓最大的单文件),波及 交互引擎 与 覆盖层系统 的行为描述。
相关文档
- 深入了解 元素系统:所有 UI 对象的基础与 pressFlags 说明。
- 了解 布局系统:脏标记、坐标系与三种容器的组织方式。
- 理解 交互引擎:输入事件如何路由(含命中链与焦点)。
- 了解 根树与层级系统:两棵树如何在 Screen 汇合。
- Developer: 快速开始:只想在界面里摆放控件时的使用侧入口