Theme 插件开发专题¶
Theme 插件用于改变 IntelliJ 系列 IDE 的视觉外观。它可以替换图标、调整 UI 控件颜色和边框、提供编辑器配色方案、添加背景图。它不应该和普通功能插件混在一起;官方建议主题插件保持独立,降低发布、审核、兼容和用户预期成本。
本章面向两类开发者:
- 想发布独立主题插件的设计/前端/插件开发者。
- 普通插件作者,需要让自己的自定义 UI 暴露主题元数据,方便主题作者适配。
Theme 插件能改什么¶
| 能力 | 文件/API | 说明 |
|---|---|---|
| IDE UI 控件颜色 | *.theme.json 的 ui |
Label、Button、Tree、List、Popup、Tabs 等控件 |
| IDE 图标颜色 | icons.ColorPalette |
全局色值替换或 Actions/Objects 调色板替换 |
| IDE 图标替换 | icons 路径映射 |
用 SVG 替换平台默认图标 |
| 编辑器配色 | editorScheme 指向 XML |
代码、行号、VCS 状态、滚动条等编辑器颜色 |
| 背景图 | background / emptyFrameBackground |
IDE 窗口和空 frame 背景 |
| 主题继承 | parentTheme |
基于已有主题继续覆盖 |
| 插件自定义 UI 主题键 | themeMetadataProvider |
普通插件暴露自己的 UI customization keys |
Theme 插件不是 UI framework。它改变现有 UI 的视觉参数,不负责新增业务功能、Action、Tool Window 或 Service。
开发方式选择¶
| 方式 | 适合场景 |
|---|---|
| DevKit Theme Project | 只做主题、希望从 IDE Wizard 快速开始、不熟悉 Gradle |
| Gradle 插件项目 | 需要 CI、自动 patch plugin.xml、构建分发包、发布到 Marketplace |
| 普通插件附带主题资源 | 不推荐;只有在插件主体就是主题体验的一部分时才考虑 |
新项目如果需要长期维护和发布,建议直接用 Gradle;一次性实验或设计验证可以从 DevKit Wizard 开始。
项目结构¶
典型主题插件结构:
theme-plugin/
build.gradle.kts
src/main/resources/
META-INF/
plugin.xml
themes/
example.theme.json
Example.xml
icons/
factory.svg
pluginIcon.svg
pluginIcon_dark.svg
核心文件:
plugin.xml:声明themeProvider。example.theme.json:主题描述文件。Example.xml:可选编辑器配色方案。- SVG 图标:可选替换平台图标或提供 Marketplace 图标。
主题资源路径以 resources 根为起点。themeProvider 的 path 和 JSON 内部路径要保持一致。
plugin.xml 声明¶
主题插件通过 themeProvider 扩展点注册:
<idea-plugin>
<id>com.example.theme</id>
<name>Example Theme</name>
<vendor email="dev@example.com">Example</vendor>
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
<themeProvider
id="com.example.theme.light"
path="/themes/example.theme.json"/>
</extensions>
</idea-plugin>
注意:
themeProvider的id必须稳定,不要复用别的主题 ID。- 一个插件可以提供多个主题,例如 light/dark 变体,每个主题用一个
themeProvider。 - 主题插件通常只依赖
com.intellij.modules.platform。 - 如果只发布主题,不要额外注册业务扩展点。
DevKit Wizard 会自动生成 themeProvider,官方特别提醒不要修改或复用已有生成 ID。Gradle 项目也应把 ID 当成长期兼容标识。
最小主题描述文件¶
*.theme.json 是主题插件最重要的文件:
{
"name": "Example Light",
"author": "Example",
"dark": false,
"editorScheme": "/themes/Example.xml",
"ui": {}
}
字段含义:
| 字段 | 说明 |
|---|---|
name |
Settings 主题下拉框里展示的名称 |
author |
主题作者 |
dark |
true 基于 Darcula,false 基于 Light |
editorScheme |
可选,关联编辑器配色 XML |
ui |
UI 控件键覆盖 |
colors |
可选,定义命名颜色 |
icons |
可选,覆盖图标颜色或替换图标 |
background |
可选,IDE 主窗口背景 |
emptyFrameBackground |
可选,空 frame 背景 |
parentTheme |
可选,继承已有主题 |
dark 不是“把所有颜色自动变暗”的开关。它决定基底主题,后续覆盖仍然要自己保证对比度、可读性和控件状态完整。
命名颜色¶
颜色可以直接写十六进制 RGB/RGBA,也可以先定义命名颜色再复用:
{
"name": "Example Light",
"dark": false,
"author": "Example",
"colors": {
"surface": "#F7F8FA",
"accent": "#2F6FED",
"danger": "#C93A3A"
},
"ui": {
"Panel.background": "surface",
"Button.default.startBackground": "accent",
"ValidationTooltip.errorBackground": "danger"
}
}
建议:
- 高频颜色用
colors命名,便于整体调色。 - 命名体现用途,不要叫
blue1、gray2。 - 少量特殊值可以直接写十六进制。
- RGBA 用八位十六进制,避免不透明度含义散落在注释里。
UI 控件键¶
UI 控件颜色放在 ui 中,键通常是 element.property:
{
"ui": {
"Panel.background": "#F7F8FA",
"Label.foreground": "#1F2328",
"TextField.background": "#FFFFFF",
"Popup.Advertiser.foreground": "#6A737D",
"ScrollBar.Mac.Transparent.thumbColor": "#00000033"
}
}
常见 property:
| property | 用途 |
|---|---|
foreground |
文本色 |
background |
背景色 |
errorForeground |
错误文本 |
borderColor |
边框色 |
selectionForeground |
选中文本色 |
selectionBackground |
选中背景色 |
inactiveBackground |
非活动状态背景 |
hoverForeground / hoverBackground |
hover 状态 |
pressedForeground / pressedBackground |
pressed 状态 |
不要只改默认态。至少检查 hover、pressed、selected、inactive、disabled、error/warning/success 等状态,否则主题在真实 IDE 中会出现“看起来正常,但一交互就不可读”的问题。
通配符覆盖¶
可以用 "*" 覆盖所有控件的同名 property:
{
"ui": {
"*": {
"background": "#F7F8FA"
},
"Label.background": "#FFFFFF"
}
}
更具体的键会覆盖通配符。通配符适合做全局基调,但风险也高:
- 容易影响未预期控件。
- 可能破坏第三方插件 UI。
- 可能让弹窗、列表、树、编辑器边栏失去层次。
实际项目中应优先使用具体键,通配符只用于非常确定的基础色。
Tab 与版本兼容¶
Tabs 是主题里最容易出现兼容问题的控件之一。平台里存在多类 Tab:
| 键 | 作用 |
|---|---|
DefaultTabs |
默认 Tab,除非被更具体类型覆盖 |
EditorTabs |
编辑器 Tab |
ToolWindow.HeaderTab |
Tool Window 头部 Tab |
TabbedPane |
设置、运行配置等普通 Swing Tabbed Pane |
SearchEverywhere.Tab |
Search Everywhere Tab |
一些属性在旧版本和新版本中名称不同。官方示例里同一个主题文件可能同时保留旧属性和新属性,让旧 IDE 忽略新属性、新 IDE 忽略已替代属性。维护多版本主题时,不要只在一个目标 IDE 里预览,应至少验证 since-build、最新稳定版和当前 EAP。
图标颜色与替换¶
图标定制放在 icons:
{
"icons": {
"ColorPalette": {
"Actions.Blue": "#2F6FED",
"Objects.Green": "#2E9D58",
"#DB5860": "#C93A3A"
},
"/actions/compile.svg": "/icons/factory.svg"
}
}
规则:
ColorPalette用于替换平台图标颜色。Actions.*用于 toolbar/action 语境。Objects.*用于文件、符号、run configuration 等对象语境。- 路径映射用于把平台默认 SVG 替换成自定义 SVG。
- 替换图标的颜色优先级高于
ColorPalette。
图标路径可以通过 UI Inspector 查看。一般从 AllIcons.Group.IconName 推导到资源路径,例如 action 图标常见形态是 /actions/name.svg。
图标替换应克制。大规模替换平台图标会提高识别成本,也更容易违反 JetBrains 图标规范。
编辑器配色方案¶
主题可以通过 editorScheme 关联编辑器配色 XML:
{
"name": "Example Dark",
"dark": true,
"editorScheme": "/themes/ExampleDark.xml",
"ui": {}
}
常见流程:
- 在 IDE Settings 中创建或复制一个 Editor Color Scheme。
- 调整语法高亮、行号、光标、选择区、VCS 文件状态等颜色。
- 导出
.icls。 - 改名为
.xml并放入 resources。 - 在
*.theme.json的editorScheme中引用。
示例片段:
<scheme name="Example Dark" version="142" parent_scheme="Darcula">
<colors>
<option name="LINE_NUMBERS_COLOR" value="7A828E"/>
<option name="FILESTATUS_ADDED" value="62CC47"/>
<option name="FILESTATUS_DELETED" value="ED864A"/>
</colors>
</scheme>
编辑器滚动条颜色有些不能从 Settings 导出,需要手动在 editor scheme XML 中维护,例如 ScrollBar.Mac.thumbColor、ScrollBar.Transparent.hoverThumbColor 等。
背景图¶
背景图通过 background 和 emptyFrameBackground 配置:
{
"background": {
"image": "/background.png",
"transparency": 12,
"fill": "scale",
"anchor": "center"
},
"emptyFrameBackground": {
"image": "/background.png",
"transparency": 20,
"fill": "scale",
"anchor": "center"
}
}
注意:
image指向 resources 中的图片。transparency范围为 1 到 100,100 表示不透明。fill常用scale。- 背景图不能影响代码可读性、对比度和长时间使用舒适度。
- Marketplace 展示图应呈现真实 IDE 使用效果,不要只展示装饰图。
主题插件最好让背景图成为可选卖点,而不是让整套主题依赖背景图才能成立。
继承已有主题¶
可以通过 parentTheme 基于已有主题继续覆盖:
{
"name": "Example Night",
"dark": true,
"parentTheme": "ParentThemeId",
"ui": {
"Panel.background": "#111827"
}
}
ParentThemeId 是目标主题 themeProvider 的 id。内置主题 ID 可以查看平台注册的 themeProvider。
继承适合:
- 做一个现有主题的轻量变体。
- 保持大部分平台视觉,只改品牌色和少量组件。
- 减少完整维护所有控件键的成本。
如果父主题未来改动,子主题也会继承变化。发布前仍要完整预览。
为自定义 UI 暴露主题元数据¶
普通插件如果有自定义 UI,并希望主题作者能修改这些颜色,应提供 *.themeMetadata.json:
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<themeMetadataProvider path="/META-INF/Example.themeMetadata.json"/>
</extensions>
</idea-plugin>
元数据示例:
{
"name": "Example Plugin",
"fixed": false,
"ui": [
{
"key": "ExamplePanel.headerForeground",
"description": "Foreground color for the Example tool window header.",
"source": "com.example.ui.ExamplePanel",
"since": "2026.1"
},
{
"key": "ExamplePanel.oldBorderColor",
"description": "Deprecated. Use ExamplePanel.borderColor instead.",
"deprecated": true,
"source": "com.example.ui.ExamplePanel"
}
]
}
代码中使用命名颜色:
private val HEADER_FOREGROUND = JBColor.namedColor(
"ExamplePanel.headerForeground",
JBColor(0x1F2328, 0xD1D5DB),
)
原则:
- 每个 key 都写
description。 - 已发布 key 不要删除,废弃时用
deprecated并说明替代项。 source指向真实 UI 组件类,方便定位。- 自定义 key 命名遵循
Object[.SubObject].[state][Part]Property。 - 不要在 key 里写
darcula、light、dark等 look-and-feel 名称。
Key 命名规则¶
推荐结构:
Object[.SubObject].[state][Part]Property
示例:
| Key | 含义 |
|---|---|
ExamplePanel.headerForeground |
Header 文本色 |
ExamplePanel.borderColor |
边框颜色 |
ExamplePanel.selectedBackground |
选中背景 |
ExamplePanel.hoverInactiveBackground |
hover 且 inactive 的背景 |
ExamplePanel.warningIconColor |
warning 图标色 |
命名约束:
- Object 和 SubObject 首字母大写。
- property 用 lowerCamelCase。
- 文本颜色用
foreground,不要用textColor。 - 边框颜色用
borderColor,不要用outlineColor。 - 对单一部件颜色使用
<Part>Color,例如separatorColor。 - 默认 active 状态不写
active。 - Swing 旧 key 不能改名,但新 key 不要模仿旧命名。
查找可覆盖的 UI key¶
官方推荐的查找方式:
| 方式 | 用途 |
|---|---|
| JSON 补全 | 在 ui 中输入时查看可用 key 和支持版本 |
| Quick Documentation | 查看 key 从哪个版本开始支持 |
| Laf Defaults | 按 element 搜索当前默认颜色 |
| UI Inspector | 从真实组件查看 foreground/background 和 key 名 |
| 平台主题实现 | 参考 High Contrast 等内置主题 |
调主题不要靠猜 key。先用 UI Inspector 或 Laf Defaults 确认控件,再在 JSON 中用补全和文档确认版本。
本地运行与预览¶
预览方式:
- 在 theme JSON 编辑器中使用 Preview Theme action。
- 对复杂样式,启动开发 IDE 实例真实测试。
- DevKit 项目可创建 Plugin run configuration。
- Gradle 项目可用
runIde或自定义开发实例任务。
验证路径:
- 安装主题插件。
- 打开 Settings | Appearance & Behavior | Appearance。
- 选择新主题并 Apply。
- 打开 Settings、Project View、Search Everywhere、Run/Debug、VCS、Editor、Terminal、Tool Window。
- 检查亮/暗、高对比、缩放、不同 OS 字体和滚动条。
只在主题 JSON 预览里看通过不够。Preview 适合快速调色,真实 IDE 实例用于发布前验证。
构建、部署与 Marketplace¶
DevKit 工作流:
- Build | Build Project 或 Build Module。
- Build | Prepare Plugin Module for Deployment。
- 生成 JAR 或 ZIP。
- 从磁盘安装到 IDE。
- 在 Appearance 设置中选择主题。
Gradle 工作流:
./gradlew buildPlugin
./gradlew verifyPlugin
./gradlew runPluginVerifier
Marketplace 发布前检查:
- 插件名和截图清楚表达主题实际效果。
- 提供亮色/暗色/高对比说明。
- 截图包含真实 IDE 界面,不只展示色板。
pluginIcon.svg和pluginIcon_dark.svg可读。since-build与实际测试矩阵匹配。- 不误导用户以为主题插件提供业务功能。
QA 清单¶
- 主题插件保持独立,不混入普通功能。
themeProviderID 稳定且唯一。*.theme.json能被 IDE 识别并出现在 Appearance 下拉框。- 所有颜色使用合法 6 位 RGB 或 8 位 RGBA。
- 高频颜色抽成命名颜色。
- hover、pressed、selected、inactive、disabled 状态可读。
- Validation、Notification、Popup、Tooltip、Editor Tabs、Tool Window Tabs 都检查过。
- 图标替换仍符合 JetBrains 图标识别习惯。
- 编辑器 scheme 与 UI theme 视觉协调。
- VCS 文件状态颜色足够区分。
- 背景图不会干扰代码和 UI 文本。
- 自定义 UI 提供
themeMetadataProvider,已发布 key 只废弃不删除。 - 在最低支持 IDE、最新稳定版和 EAP 上预览过。
- Marketplace 截图展示真实 IDE 场景。