Native Settings UI Lib
A utility library that streamlines custom UI creation by auto-injecting tabs and controls directly into the built-in settings menu
By XiaohaiMod
| Last updated | a day ago |
| Total downloads | 77 |
| Total rating | 0 |
| Categories | Libraries |
| Dependency string | XiaohaiMod-Native_Settings_UI_Lib-1.0.0 |
| Dependants | 0 other packages depend on this package |
This mod requires the following mods to function
BepInEx-BepInExPack
BepInEx pack for Mono Unity games. Preconfigured and ready to use.
Preferred version: 5.4.2304README
YapYap Native Settings UI Lib(Yap_NativeSettingsUI)
简体中文
一个用于 YapYap(BepInEx) 的设置界面注入库:在游戏自带 UISettings 界面中,自动创建自定义 Tab 与 Section,并在其中生成按钮、开关、下拉、滑条、标签、编辑框等控件。
本 README 重点介绍 公开接口 与参数含义。
快速开始
典型用法:
var tab = NativeSettingsUI.RegisterTab(
guid: "com.yourmod.settings.tab",
title: new LocalText("TAB_TITLE", "我的设置", "My Settings"),
showInGame: true
);
tab.CreateToggle(
id: "Toggle_Enabled",
settingKey: "com.yourmod.Enabled",
title: new LocalText("ENABLED", "启用", "Enabled"),
initialValue: true,
onChanged: v => enabled = v,
showInGame: true
);
核心概念
1) Tab / Section 注入
RegisterTab(...) 会在 UISettings 可用时,自动:
- 在左侧 Tab 列表创建一个按钮(Tab)
- 在右侧 Section 区创建一个面板(Section)
- 点击 Tab 时切换到该 Section(通过绑定到
UISettings.sections实现)
2) LocalText(简易本地化文本)
LocalText 用来提供“中文/英文”两套文本:
new LocalText(key: "EXAMPLE", chinese: "中文", english: "English")
- 如果你不打算制作多语言 UI,可以把
chinese或者english留空,但是至少要提供一个非空字符串 - 当前语言为中文(
Chinese/ChineseSimplified/ChineseTraditional)时显示chinese - 否则显示
english - 该库会监听语言变化并自动刷新绑定过的文本
3) UiRef<T>(延迟拿到真实 UI 引用)
UISettings 的对象不是在 Awake 立刻存在,控件会“稍后”才被克隆/创建出来。
CreateXxx() 返回 UiRef<T>:
IsReady:是否已经拿到了真实 UI 组件引用Value:真实引用(未就绪时为null)Ready:当真实引用出现时触发
UiRef<TMP_Text> labelRef = tab.CreateLabel(...);
labelRef.Ready += tmp =>
{
// tmp 就是真实的 TMP_Text
};
公共接口:NativeSettingsUI
命名空间:Yap_NativeSettingsUI
RegisterTab
public static SettingsTab RegisterTab(string guid, LocalText title, bool showInGame)
guid:Tab 的唯一标识(建议用你的 ModId 前缀),重复注册同 guid 会返回同一个 Tabtitle:Tab 标题(支持中/英切换)showInGame:是否在“游戏内打开的设置界面”也显示该 Tab(Tab 自身不开启则控件再开也不会显示)
BindText / UnbindText
用于给某个 TMP_Text 绑定/解绑 LocalText 的自动刷新逻辑。
public static void BindText(TMP_Text tmp, LocalText text)
public static void UnbindText(TMP_Text tmp)
适用场景:
- 你想让某个文本跟随语言变化:用
BindText - 你想把某个标签改成“运行时动态文本”,不再被本地化刷新覆盖:先
UnbindText再tmp.text = ...
公共接口:SettingsTab(创建控件)
RegisterTab(...) 返回 SettingsTab,所有控件都在 Tab 上创建。
通用参数说明
以下参数在多数控件中都有:
id- 控件对象名(用于查找/避免重复创建)
- 建议保持唯一,例如:
"Toggle_Enabled"、"Button_Save"
showInGame- 该控件是否在“游戏内设置界面”显示
- 前提:Tab 的
showInGame=true
preferredSize(可选)- 期望尺寸(宽高)
- 不传则使用游戏原生模板的默认尺寸/布局
- 当你给某些控件设置了较大的宽度时,库会启用“自定义两列流式布局”,以支持跨列/换行
anchoredPositionOffset(可选)- 在最终位置基础上做少量偏移(用于微调)
- 注意:如果父级布局组件会重排,偏移可能会被布局覆盖或产生不可预期效果
CreateButton
public UiRef<Button> CreateButton(
string id,
LocalText text,
Action onClick,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text:按钮显示文本(中/英)onClick:点击回调
CreateLabel
public UiRef<TMP_Text> CreateLabel(
string id,
LocalText text,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text:标签文本(中/英)
CreateToggle
public UiRef<UISettingToggle> CreateToggle(
string id,
string settingKey,
LocalText title,
bool initialValue,
Action<bool> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
title:控件标题(中/英)initialValue:初始值onChanged:值变化回调settingKey:持久化键名(见下文“settingKey 是什么”)
CreateDropdownString
public UiRef<UISettingDropdownString> CreateDropdownString(
string id,
string settingKey,
LocalText title,
IList<string> options,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
options:下拉可选项(字符串列表)initialValue:初始选中项onChanged:选择变化回调settingKey:持久化键名
CreateSliderInt
public UiRef<UICustomSlider> CreateSliderInt(
string id,
string settingKey,
LocalText title,
int minValue,
int maxValue,
int initialValue,
Action<int> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
minValue / maxValue:整数范围initialValue:初始值(会被 clamp 到范围内)onChanged:值变化回调settingKey:持久化键名
CreateInputString(编辑框)
public UiRef<TMP_InputField> CreateInputString(
string id,
string settingKey,
LocalText title,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
实现说明(与示例一致):
- 基于 Slider 模板克隆
- 删除
Slider子节点下的Value、Fill Area、Handle - 将
Slider子节点重命名为Input - 销毁根对象上的
YAPYAP.UICustomSlider组件 - 确保
InputField对象被激活(模板里它可能默认是未激活)
数据行为:
- 若
settingKey非空:启动时PlayerPrefs.GetString(settingKey, initialValue) - 在
onEndEdit时保存:PlayerPrefs.SetString(settingKey, v)并回调onChanged(v)
settingKey 是什么?
settingKey 用于 游戏原生设置系统的持久化键名(本质是 PlayerPrefs 的 key)。
推荐规则:
- 每个控件一个唯一 key
- 使用 ModId 做前缀,避免与别的 Mod 或游戏本体冲突
例如:
com.yourmod.Toggle.Enabledcom.yourmod.Dropdown.Modecom.yourmod.Input.Note
常见用法示例
运行时修改 Label 文本(不被本地化刷新覆盖)
UiRef<TMP_Text> labelRef = tab.CreateLabel(
id: "Label_Runtime",
text: new LocalText("RUNTIME", "等待加载", "Waiting for UI")
);
labelRef.Ready += tmp =>
{
NativeSettingsUI.UnbindText(tmp);
tmp.text = "Runtime label ready.";
};
下拉只在主菜单显示,不在游戏内显示
tab.CreateDropdownString(
id: "Dropdown_Mode",
settingKey: "com.yourmod.Mode",
title: new LocalText("MODE", "模式", "Mode"),
options: new [] { "Normal", "Hard" },
initialValue: "Normal",
onChanged: v => gameMode = v ,
showInGame: false
);
作者 / Author
- 作者: 小海 (XiaoHai)
- Bilibili: https://space.bilibili.com/2055787437
- 邮箱: [email protected]
English
An injection library MOD for YapYap (BepInEx). It hooks into the built-in UISettings screen, automatically creates a custom Tab + Section, and provides helper APIs to generate common controls such as buttons, toggles, dropdowns, sliders, labels, and input fields.
Quick Start
Typical usage:
var tab = NativeSettingsUI.RegisterTab(
guid: "com.yourmod.settings.tab",
title: new LocalText("TAB_TITLE", "我的设置", "My Settings"),
showInGame: true
);
tab.CreateToggle(
id: "Toggle_Enabled",
settingKey: "com.yourmod.Enabled",
title: new LocalText("ENABLED", "启用", "Enabled"),
initialValue: true,
onChanged: v => enabled = v,
showInGame: true
);
Core Concepts
1) Tab / Section Injection
RegisterTab(...) automatically does the following when UISettings becomes available:
- Creates a Tab button in the left-side Tab list
- Creates a corresponding Section panel in the right-side content area
- Wires Tab switching to show the Section (by binding into
UISettings.sections)
2) LocalText (Lightweight Localization)
LocalText holds two versions of a string (Chinese / English):
new LocalText(key: "EXAMPLE", chinese: "中文", english: "English")
- If you don't plan to build a multilingual UI, you can leave the Chinese text empty.
- When the current language is Chinese (
Chinese/ChineseSimplified/ChineseTraditional), the library showschinese - Otherwise it shows
english - The library listens for language changes and refreshes bound texts automatically
3) UiRef<T> (Deferred UI Reference)
UISettings objects do not necessarily exist at Awake, and controls are created later.
Each CreateXxx() returns UiRef<T>:
IsReady: whether the real component instance is availableValue: the actual UI component (null before ready)Ready: fired once the actual component instance becomes available
UiRef<TMP_Text> labelRef = tab.CreateLabel(...);
labelRef.Ready += tmp =>
{
// tmp is the real TMP_Text instance
};
Public API: NativeSettingsUI
Namespace: Yap_NativeSettingsUI
RegisterTab
public static SettingsTab RegisterTab(string guid, LocalText title, bool showInGame)
guid: Unique tab id. Registering the same guid multiple times returns the sameSettingsTabinstance. Recommended to prefix with your ModId.title: Tab title (Chinese/English switching supported)showInGame: Whether this tab should also appear in the in-game settings UI. If the tab itself is not shown in-game, controls won't be shown in-game either.
BindText / UnbindText
Bind or unbind the automatic LocalText refresh behavior for a TMP_Text.
public static void BindText(TMP_Text tmp, LocalText text)
public static void UnbindText(TMP_Text tmp)
Use cases:
- You want a text to follow language switching: use
BindText - You want a label to become a runtime-only dynamic string (not overridden by localization refresh): call
UnbindTextand then settmp.text = ...
Public API: SettingsTab (Creating Controls)
RegisterTab(...) returns a SettingsTab. All controls are created from the tab instance.
Common Parameters
Most control creation methods share these parameters:
id- The control object name (used for lookup and to avoid duplicating controls)
- Should be unique, e.g.
"Toggle_Enabled","Button_Save"
showInGame- Whether the control is shown in the in-game settings UI
- Requires the tab itself to be created with
showInGame=true
preferredSize(optional)- Desired size (width/height)
- If omitted, the game template’s default size/layout is used
- When some controls become “too wide”, the library enables a custom two-column flow layout to support wrapping and full-row controls
anchoredPositionOffset(optional)- Small offset applied on top of the final position (for fine tuning)
- Note: If a parent layout component drives positioning, offsets may be overridden or become unpredictable
CreateButton
public UiRef<Button> CreateButton(
string id,
LocalText text,
Action onClick,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text: Button text (Chinese/English)onClick: Click callback
CreateLabel
public UiRef<TMP_Text> CreateLabel(
string id,
LocalText text,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text: Label text (Chinese/English)
CreateToggle
public UiRef<UISettingToggle> CreateToggle(
string id,
string settingKey,
LocalText title,
bool initialValue,
Action<bool> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
title: Control title (Chinese/English)initialValue: Initial valueonChanged: Callback when the value changessettingKey: Persistent key (see “What is settingKey?” below)
CreateDropdownString
public UiRef<UISettingDropdownString> CreateDropdownString(
string id,
string settingKey,
LocalText title,
IList<string> options,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
options: Dropdown options (string list)initialValue: Initially selected itemonChanged: Callback when selection changessettingKey: Persistent key
CreateSliderInt
public UiRef<UICustomSlider> CreateSliderInt(
string id,
string settingKey,
LocalText title,
int minValue,
int maxValue,
int initialValue,
Action<int> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
minValue / maxValue: Integer rangeinitialValue: Initial value (clamped into the range)onChanged: Callback when value changessettingKey: Persistent key
CreateInputString (Input Field)
public UiRef<TMP_InputField> CreateInputString(
string id,
string settingKey,
LocalText title,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
Implementation notes (as in the example):
- Clones from the Slider template
- Deletes
Value,Fill Area,Handleunder theSliderchild - Renames the
Sliderchild toInput - Destroys the
YAPYAP.UICustomSlidercomponent on the root - Ensures the
InputFieldobject is active (the template may keep it disabled by default)
Data behavior:
- If
settingKeyis non-empty: initial text usesPlayerPrefs.GetString(settingKey, initialValue) - On
onEndEdit: savesPlayerPrefs.SetString(settingKey, v)and callsonChanged(v)
What is settingKey?
settingKey is the persistent key name used by the game’s settings system (effectively a PlayerPrefs key).
Recommended practice:
- Use a unique key per control
- Prefix with your ModId to avoid collisions with other mods or the base game
Examples:
com.yourmod.Toggle.Enabledcom.yourmod.Dropdown.Modecom.yourmod.Input.Note
Common Usage Examples
Update a label at runtime (and prevent localization from overriding it)
UiRef<TMP_Text> labelRef = tab.CreateLabel(
id: "Label_Runtime",
text: new LocalText("RUNTIME", "等待加载", "Waiting for UI")
);
labelRef.Ready += tmp =>
{
NativeSettingsUI.UnbindText(tmp);
tmp.text = "Runtime label ready.";
};
Show a dropdown only in the main menu (not in-game)
tab.CreateDropdownString(
id: "Dropdown_Mode",
settingKey: "com.yourmod.Mode",
title: new LocalText("MODE", "模式", "Mode"),
options: new [] { "Normal", "Hard" },
initialValue: "Normal",
onChanged: v => { },
showInGame: false
);
Author
- Author: XiaoHai (小海)
- Bilibili: https://space.bilibili.com/2055787437
- Email: [email protected]