# 插件设置界面(PluginPreference)

PluginPreference 用于构建插件的配置界面,提供了丰富的设置选项类型,包括文本显示、输入框、开关、单选列表等。设置数据会自动保存到 SharedPreferences,无需手动处理存储逻辑。

# 快速开始

public class MyPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        // 设置标题
        builder.title("插件设置");

        // 添加分组标题
        builder.addHeader("基础设置");

        // 添加开关选项
        builder.addSwitch("启用功能", "enable_feature")
                .defaultValue(true)
                .summaryOn("已启用")
                .summaryOff("已禁用");

        // 添加输入选项
        builder.addInput("API 地址", "api_url")
                .defaultValue("https://api.example.com")
                .valueAsSummary();
    }
}

在 build.gradle 中配置:

mtPlugin {
    // 主设置界面(可选)
    mainPreference = "com.example.myplugin.MyPreference"
}

提示:关于完整的项目配置说明,请查看 开发环境搭建

# 接口概览

# PluginPreference 接口

方法 说明
onBuild() 构建设置界面的回调方法

# Builder 接口

方法 说明
title() 设置界面标题
subtitle() 设置界面副标题
addHeader() 添加分组标题头
addText() 添加纯文本显示项
addInput() 添加文本输入选项
addSwitch() 添加开关选项
addList() 添加单选列表选项
onPreferenceChange() 注册设置项值变化监听器
onCreated() 注册界面创建完成监听器

# Header 接口

方法 说明
visible() 设置可见性
enable() 设置启用状态

# Text 接口

方法 说明
summary() 设置摘要文本
url() 设置点击后跳转的URL
onClick() 设置自定义点击事件
interceptClick() 设置点击拦截器
visible() 设置可见性
enable() 设置启用状态

# Input 接口

方法 说明
defaultValue() 设置默认值
summary() 设置摘要文本
hint() 设置输入框提示文本
valueAsSummary() 使用当前值作为摘要
inputType() 设置输入类型
validator() 设置输入校验器
interceptClick() 设置点击拦截器
visible() 设置可见性
enable() 设置启用状态

# Switch 接口

方法 说明
defaultValue() 设置默认状态
summary() 设置摘要文本
summaryOn() 设置开启时的摘要
summaryOff() 设置关闭时的摘要
interceptClick() 设置点击拦截器
visible() 设置可见性
enable() 设置启用状态

# List 接口

方法 说明
defaultValue() 设置默认选中值
summary() 设置摘要文本
addItem() 添加子选项
interceptClick() 设置点击拦截器
visible() 设置可见性
enable() 设置启用状态

# PreferenceScreen 接口

方法 说明
recreate() 重新创建设置界面
getTitle() / setTitle() 获取/设置标题
getSubtitle() / setSubtitle() 获取/设置副标题
findHeader() / requireHeader() 查找分组标题头
findPreference() / requirePreference() 查找设置选项

# PreferenceHeader 接口

方法 说明
getPreferenceScreen() 获取所属的设置界面实例
getKey() 获取键名
getTitle() / setTitle() 获取/设置标题
isEnabled() / setEnabled() 获取/设置启用状态
isVisible() / setVisible() 获取/设置可见性

# PreferenceItem 接口

方法 说明
getPreferenceScreen() 获取所属的设置界面实例
getKey() 获取键名
getTitle() / setTitle() 获取/设置标题
getSummary() / setSummary() 获取/设置摘要
isEnabled() / setEnabled() 获取/设置启用状态
isVisible() / setVisible() 获取/设置可见性

# 创建设置界面

# onBuild

void onBuild(PluginContext context, Builder builder)

构建设置界面时的回调方法,在此方法中通过 Builder 添加各种设置选项。

参数:

  • context - 插件上下文,提供插件运行环境
  • builder - 界面构建器,用于添加设置选项

示例:

public class MyPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("设置");
        builder.addSwitch("启用", "enable").defaultValue(true);
    }
}

# 界面配置

# title 和 subtitle

Builder title(CharSequence title)
Builder subtitle(CharSequence subtitle)

设置界面顶栏的标题和副标题。

参数:

  • title - 标题文本,默认为"设置",支持 {key} 格式的本地化文本
  • subtitle - 副标题文本,默认为空,支持 {key} 格式的本地化文本

示例:

builder.title("插件设置")
       .subtitle("配置插件的各项参数");

// 使用本地化文本
builder.title("{settings}")
       .subtitle("{settings_description}");

# addHeader

Header addHeader(CharSequence title)
Header addHeader(CharSequence title, String key)

添加一个分组标题头,用于将相关的设置选项进行分组显示。

参数:

  • title - 分组标题文本,支持 {key} 格式的本地化文本
  • key - 可选,分组标题头的键名,用于后续通过 PreferenceScreen.findHeader()/requireHeader() 查找

返回值: Header 实例,可进行进一步配置

示例:

builder.addHeader("基础设置");
builder.addSwitch("选项1", "key1");
builder.addSwitch("选项2", "key2");

builder.addHeader("高级设置");
builder.addInput("选项3", "key3");

// 带 key 的分组标题头,便于后续动态访问
builder.addHeader("可控设置", "controllable_header")
       .visible(true)
       .enable(true);

# onPreferenceChange

Builder onPreferenceChange(OnPreferenceChangeListener listener)

注册设置项值变化时的回调监听器。当用户修改 Input、Switch、List 设置项的值时,会触发此监听器的回调。

参数:

  • listener - 设置项值变化的监听器

监听器接口:

interface OnPreferenceChangeListener {
    void onChange(PluginUI pluginUI, PreferenceItem preferenceItem, Object newValue);
}
  • pluginUI - 插件UI实例
  • preferenceItem - 内容发生变更的设置选项实例
  • newValue - 设置选项的新值,对于 Input 和 List 类型为 String,对于 Switch 类型为 Boolean

示例:

builder.onPreferenceChange((pluginUI, preferenceItem, newValue) -> {
    String key = preferenceItem.getKey();
    if ("theme".equals(key)) {
        // 主题变更时的处理逻辑
        pluginUI.toast("主题已切换为:" + newValue);
    }
});

# onCreated

Builder onCreated(OnPreferenceScreenCreatedListener listener)

注册设置界面创建完成时的回调监听器。当设置界面构建完成后,可以通过此监听器获取 PreferenceScreen 实例,用于动态修改界面元素或执行其他初始化操作。

参数:

  • listener - 界面创建完成的监听器

监听器接口:

interface OnPreferenceScreenCreatedListener {
    void onPreferenceScreenCreated(PluginUI pluginUI, PreferenceScreen preferenceScreen);
}
  • pluginUI - 插件UI实例
  • preferenceScreen - 已创建完成的设置界面实例

示例:

builder.onCreated((pluginUI, screen) -> {
    // 界面创建完成后,动态修改标题
    screen.setTitle("动态标题");

    // 根据条件显示或隐藏某个设置项
    PreferenceItem advancedItem = screen.findPreference("advanced_option");
    if (advancedItem != null) {
        advancedItem.setVisible(isAdvancedUser());
    }
});

# 分组标题头(Header)

# visible

Header visible(boolean visible)

设置分组标题的可见性。

参数:

  • visible - true 为可见,false 为隐藏

# enable

Header enable(boolean enable)

设置分组标题的启用状态。

参数:

  • enable - true 为启用,false 为禁用(显示为灰色)

示例:

// 根据条件控制分组标题头的显示
boolean showAdvanced = preferences.getBoolean("show_advanced", false);
builder.addHeader("高级设置", "advanced_header")
       .visible(showAdvanced);

# 设置选项

所有设置选项的 key 参数用于 SharedPreferences 的键名,通过 context.getPreferences() 可以获取和修改这些值。

# 通用方法

以下方法在 Text、Input、Switch、List 接口中都可用:

# visible

visible(boolean visible)

设置选项的可见性。

参数:

  • visible - true 为可见,false 为隐藏

# enable

enable(boolean enable)

设置选项的启用状态。

参数:

  • enable - true 为启用,false 为禁用(显示为灰色且不可点击)

# interceptClick

interceptClick(OnClickInterceptListener listener)

设置点击拦截器。当用户点击该选项时,会触发拦截器的回调方法,可通过返回值控制是否继续执行默认行为。

参数:

  • listener - 点击拦截器

拦截器接口:

interface OnClickInterceptListener {
    boolean onClick(PluginUI pluginUI, PreferenceItem preferenceItem);
}
  • 返回 true 表示已拦截点击事件,不再执行默认行为
  • 返回 false 表示继续执行默认行为

示例:

// 在执行默认行为前进行确认
builder.addSwitch("危险选项", "dangerous_option")
       .interceptClick((pluginUI, preferenceItem) -> {
           pluginUI.buildDialog()
                   .setTitle("警告")
                   .setMessage("确定要修改此选项吗?")
                   .setPositiveButton("{ok}", (dialog, which) -> {
                       // 用户确认后,手动切换开关状态
                       SharedPreferences prefs = context.getPreferences();
                       boolean current = prefs.getBoolean("dangerous_option", false);
                       prefs.edit().putBoolean("dangerous_option", !current).apply();
                       // 刷新界面
                       preferenceItem.getPreferenceScreen().recreate();
                   })
                   .setNegativeButton("{cancel}", null)
                   .show();
           return true; // 拦截默认行为
       });

# 文本选项(Text)

# addText

Text addText(CharSequence title)
Text addText(CharSequence title, String key)

添加一个纯文本显示项,可用于显示说明信息或链接。

参数:

  • title - 显示的标题文本,支持 {key} 格式的本地化文本
  • key - 可选,文本选项的键名,用于后续通过 PreferenceScreen.findPreference()/requirePreference() 查找

返回值: Text 实例,可进行进一步配置

# summary

Text summary(CharSequence summary)

设置摘要文本,显示在标题下方的详细说明信息。

参数:

  • summary - 摘要文本内容,支持 {key} 格式的本地化文本

示例:

builder.addText("关于")
       .summary("插件版本 1.0.0");

# url

Text url(String url)

设置点击后跳转的URL地址。

参数:

  • url - 要跳转的URL地址,应为有效的HTTP/HTTPS链接

注意: 如果同时设置了 onClick() 监听器,自定义点击事件的优先级更高,URL跳转将不会执行。

示例:

builder.addText("官方网站")
       .summary("访问插件官方网站")
       .url("https://example.com");

# onClick

Text onClick(OnTextItemClickListener listener)

设置自定义点击事件监听器。

interceptClick() 的主要区别:

  • onClick() 的监听器不需要返回值,简化代码编写,且设置后会拦截默认行为(URL 跳转)
  • interceptClick() 需要返回 boolean 值来控制是否继续执行默认行为

如果只需要处理点击事件而不关心默认行为,推荐使用 onClick()

参数:

  • listener - 点击事件监听器

监听器接口:

interface OnTextItemClickListener {
    void onClick(PluginUI pluginUI, PreferenceItem preferenceItem);
}
  • pluginUI - PluginUI 实例,可用于显示对话框等
  • item - 被点击的文本项实例,可通过 setTitle()setSummary() 动态修改

示例:

// 计数器示例
AtomicInteger count = new AtomicInteger();
builder.addText("点击计数")
       .summary("点击了 0 次")
       .onClick((pluginUI, item) -> {
           item.setSummary("点击了 " + count.incrementAndGet() + " 次");
       });

# 输入选项(Input)

# addInput

Input addInput(CharSequence title, String key)

添加一个文本输入选项,用户可以输入文本内容,值以 String 类型存储到 SharedPreferences。

参数:

  • title - 选项标题,支持 {key} 格式的本地化文本
  • key - 存储选项值的键名

返回值: Input 实例,可进行进一步配置

# defaultValue

Input defaultValue(CharSequence defaultValue)

设置输入框的默认值。

参数:

  • defaultValue - 默认文本内容,支持 {key} 格式的本地化文本

# summary

Input summary(CharSequence summary)

设置摘要文本,显示在标题下方的说明信息。

参数:

  • summary - 摘要文本内容,支持 {key} 格式的本地化文本

# hint

Input hint(CharSequence hint)

设置输入框的提示文本,当输入框为空时显示的灰色提示信息。

参数:

  • hint - 提示文本内容,支持 {key} 格式的本地化文本

示例:

builder.addInput("API 密钥", "api_key")
       .hint("请输入您的 API 密钥")
       .valueAsSummary();

# valueAsSummary

Input valueAsSummary()

使用当前输入值作为摘要显示。此选项会覆盖通过 summary() 方法设置的摘要。

# inputType

Input inputType(int inputType)

设置文本输入类型,用于控制软键盘类型和输入限制。

参数:

  • inputType - 输入类型,参考 android.text.InputType 常量

示例:

import android.text.InputType;

// 数字输入
builder.addInput("端口", "port")
       .inputType(InputType.TYPE_CLASS_NUMBER)
       .defaultValue("8080");

// 密码输入
builder.addInput("密码", "password")
       .inputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);

# validator

Input validator(Validator validator)

设置输入内容校验器,用于检测用户输入内容的格式是否正确。

参数:

  • validator - 校验器实例

校验器接口:

interface Validator {
    String validate(String value);
}
  • 校验通过返回 null
  • 校验失败返回错误信息(支持 {key} 格式的本地化文本)

示例:

builder.addInput("端口号", "port")
       .validator(value -> {
           if (value.isEmpty()) {
               return "端口号不能为空";
           }
           try {
               int port = Integer.parseInt(value);
               if (port < 1 || port > 65535) {
                   return "端口号范围:1-65535";
               }
               return null;  // 校验通过
           } catch (NumberFormatException e) {
               return "请输入有效的数字";
           }
       });

完整示例:

builder.addInput("服务器地址", "server_url")
       .defaultValue("https://api.example.com")
       .valueAsSummary();

builder.addInput("端口", "port")
       .inputType(InputType.TYPE_CLASS_NUMBER)
       .defaultValue("8080")
       .validator(value -> {
           try {
               int port = Integer.parseInt(value);
               return (port >= 1 && port <= 65535) ? null : "端口号范围:1-65535";
           } catch (NumberFormatException e) {
               return "请输入有效的数字";
           }
       });

# 开关选项(Switch)

# addSwitch

Switch addSwitch(CharSequence title, String key)

添加一个开关选项,用户可以开启或关闭,值以 boolean 类型存储到 SharedPreferences。

参数:

  • title - 选项标题,支持 {key} 格式的本地化文本
  • key - 存储选项值的键名

返回值: Switch 实例,可进行进一步配置

# defaultValue

Switch defaultValue(boolean defaultValue)

设置开关的默认状态。

参数:

  • defaultValue - true 为开启,false 为关闭

# summary

Switch summary(CharSequence summary)

设置摘要文本,显示在标题下方的说明信息。

参数:

  • summary - 摘要文本内容,支持 {key} 格式的本地化文本

# summaryOn 和 summaryOff

Switch summaryOn(CharSequence summary)
Switch summaryOff(CharSequence summary)

设置开关为"开启"或"关闭"状态时显示的摘要。这两个方法会覆盖通过 summary() 方法设置的摘要。

参数:

  • summary - 对应状态下的摘要文本,支持 {key} 格式的本地化文本

示例:

// 固定摘要
builder.addSwitch("启用调试模式", "debug_mode")
       .defaultValue(false)
       .summary("开启后会输出详细日志");

// 动态摘要
builder.addSwitch("自动更新", "auto_update")
       .defaultValue(true)
       .summaryOn("已启用自动更新")
       .summaryOff("已禁用自动更新");

# 列表选项(List)

# addList

List addList(CharSequence title, String key)

添加一个单选列表选项,用户可以从预定义的选项中选择一个,值以 String 类型存储到 SharedPreferences。

参数:

  • title - 选项标题,支持 {key} 格式的本地化文本
  • key - 存储选项值的键名

返回值: List 实例,可进行进一步配置

# defaultValue

List defaultValue(String defaultValue)

设置列表的默认选中值。

参数:

  • defaultValue - 默认选中项的值

# summary

List summary(CharSequence summary)

设置摘要文本,显示在标题下方的说明信息。

参数:

  • summary - 摘要文本内容,支持 {key} 格式的本地化文本

# addItem

Item addItem(CharSequence name, String value)

添加一个子选项到列表中。

参数:

  • name - 子选项显示名称,支持 {key} 格式的本地化文本
  • value - 子选项对应的值

返回值: Item 实例,可进行进一步配置或添加更多选项

# Item.summary

Item summary(CharSequence summary)

设置该子选项被选中时显示的摘要。此选项会覆盖父列表通过 summary() 方法设置的摘要。

参数:

  • summary - 选中时的摘要文本,支持 {key} 格式的本地化文本

示例:

// 基础用法
builder.addList("语言", "language")
       .defaultValue("zh-CN")
       .addItem("简体中文", "zh-CN")
       .addItem("English", "en")
       .addItem("日本語", "ja");

// 带动态摘要
builder.addList("主题", "theme")
       .summary("未选择主题")
       .addItem("浅色", "light").summary("当前主题:浅色")
       .addItem("深色", "dark").summary("当前主题:深色")
       .addItem("跟随系统", "auto").summary("当前主题:跟随系统");

# 动态界面控制

# PreferenceScreen

设置界面实例,用于在设置界面创建完成后动态访问和修改界面元素。

# recreate

void recreate()

重新创建设置界面。调用此方法会重新执行 onBuild() 方法,重新构建整个设置界面。

# getTitle / setTitle

CharSequence getTitle()
void setTitle(CharSequence title)

获取/设置设置界面的标题。支持 {key} 格式的本地化文本。

# getSubtitle / setSubtitle

CharSequence getSubtitle()
void setSubtitle(CharSequence subtitle)

获取/设置设置界面的副标题。支持 {key} 格式的本地化文本。

# findHeader / requireHeader

PreferenceHeader findHeader(String key)
PreferenceHeader requireHeader(String key)

根据 key 查找分组标题头。

参数:

  • key - 分组标题头的键名

返回值:

  • findHeader() - 找到的 PreferenceHeader 实例,未找到返回 null
  • requireHeader() - 找到的 PreferenceHeader 实例,未找到时抛出 IllegalArgumentException

# findPreference / requirePreference

PreferenceItem findPreference(String key)
PreferenceItem requirePreference(String key)

根据 key 查找设置选项。

参数:

  • key - 设置选项的键名

返回值:

  • findPreference() - 找到的 PreferenceItem 实例,未找到返回 null
  • requirePreference() - 找到的 PreferenceItem 实例,未找到时抛出 IllegalArgumentException

# PreferenceHeader

分组标题头实例,用于在设置界面创建完成后动态访问和修改分组标题头。

方法 说明
getPreferenceScreen() 获取所属的设置界面实例
getKey() 获取分组标题头的键名
getTitle() / setTitle() 获取/设置标题文本
isEnabled() / setEnabled() 获取/设置启用状态
isVisible() / setVisible() 获取/设置可见性

# PreferenceItem

设置选项实例,用于在设置界面创建完成后动态访问和修改设置选项。

方法 说明
getPreferenceScreen() 获取所属的设置界面实例
getKey() 获取设置选项的键名
getTitle() / setTitle() 获取/设置标题文本
getSummary() / setSummary() 获取/设置摘要文本
isEnabled() / setEnabled() 获取/设置启用状态
isVisible() / setVisible() 获取/设置可见性

示例:

builder.addText("版本信息", "version_info")
       .summary("加载中...");

builder.onCreated((pluginUI, screen) -> {
    // 界面创建完成后,异步获取版本信息并更新
    PreferenceItem versionItem = screen.requirePreference("version_info");
    fetchVersionAsync(version -> {
        versionItem.setSummary("当前版本:" + version);
    });
});

# 数据存储

设置选项的值会自动保存到 SharedPreferences,可以通过 PluginContext.getPreferences() 获取和修改。

// 在 onBuild 中添加设置选项
builder.addSwitch("启用功能", "enable_feature").defaultValue(true);
builder.addInput("API地址", "api_url").defaultValue("https://api.example.com");

// 在插件其他地方读取设置值
SharedPreferences preferences = context.getPreferences();
boolean enabled = preferences.getBoolean("enable_feature", true);
String apiUrl = preferences.getString("api_url", "https://api.example.com");

// 修改设置值
preferences.edit()
    .putBoolean("enable_feature", false)
    .putString("api_url", "https://newapi.example.com")
    .apply();

# 配置主设置界面

要配置主设置界面,需要在实现 PluginPreference 接口后,在模块的 build.gradle 中配置 mainPreference 字段。

# 在 build.gradle 中配置

mtPlugin {
    pluginID = "com.example.myplugin"
    versionCode = 1
    versionName = "v1.0"
    name = "示例插件"

    // 主设置界面
    mainPreference = "com.example.myplugin.MyPreference"

    interfaces = [
        "com.example.myplugin.MyTranslationEngine",
        // 其他接口...
    ]
}

配置说明:

  • mainPreference - 主设置界面类的完整路径(包名 + 类名)
  • 配置主设置界面是可选的,如果插件不需要主设置界面可以不配置
  • 用户在插件管理界面查看插件信息时,可点击设置按钮打开主设置界面
  • 插件可以有多个设置界面,但只有配置为 mainPreference 的才是主设置界面

提示:完整的 mtPlugin {} 配置说明请查看 开发环境搭建

# 打开设置界面

可以通过 pluginUI.showPreference() 方法在代码中打开任意设置界面。

void showPreference(Class<? extends PluginPreference> clazz)

参数:

  • clazz - 设置界面类,需实现 PluginPreference 接口,传入 null 则打开主设置界面

示例:

// 打开主设置界面
pluginUI.showPreference(null);

// 打开指定的设置界面
pluginUI.showPreference(AdvancedSettings.class);

// 在按钮点击事件中打开设置
builder.addText("高级设置")
       .summary("配置高级选项")
       .onClick((pluginUI, item) -> {
           pluginUI.showPreference(AdvancedSettings.class);
       });

应用场景:

  • 在主设置界面中提供入口跳转到子设置界面
  • 在文本选项的点击事件中打开相关设置
  • 从其他插件功能中打开设置界面

# 完整示例

# 基础设置界面

public class MyPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("插件设置");

        builder.addHeader("基础设置");

        builder.addSwitch("启用插件", "plugin_enabled")
                .defaultValue(true)
                .summaryOn("插件已启用")
                .summaryOff("插件已禁用");

        builder.addInput("用户名", "username")
                .defaultValue("")
                .valueAsSummary();

        builder.addList("语言", "language")
                .defaultValue("zh-CN")
                .addItem("简体中文", "zh-CN").summary("使用简体中文")
                .addItem("English", "en").summary("Use English");

        builder.addHeader("关于");

        builder.addText("版本")
                .summary("1.0.0");

        builder.addText("官方网站")
                .summary("访问插件官方网站")
                .url("https://example.com");
    }
}

# 动态界面控制

public class DynamicPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("动态设置");

        SharedPreferences preferences = context.getPreferences();
        boolean showAdvanced = preferences.getBoolean("show_advanced", false);

        builder.addSwitch("显示高级选项", "show_advanced")
                .defaultValue(false);

        // 根据条件控制高级选项的显示
        builder.addHeader("高级选项", "advanced_header")
                .visible(showAdvanced);

        builder.addInput("高级参数", "advanced_param")
                .visible(showAdvanced);

        // 监听设置变化
        builder.onPreferenceChange((pluginUI, item, newValue) -> {
            if ("show_advanced".equals(item.getKey())) {
                // 当"显示高级选项"改变时,重建界面
                item.getPreferenceScreen().recreate();
            }
        });
    }
}

# 自定义对话框

public class AdvancedPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("高级设置");

        SharedPreferences preferences = context.getPreferences();

        // 自定义输入对话框
        builder.addText("自定义输入")
                .summary(getSummary(preferences))
                .onClick((pluginUI, item) -> {
                    // 创建输入框
                    PluginView view = pluginUI.buildVerticalLayout()
                            .addEditText("input")
                            .text(preferences.getString("custom_value", ""))
                            .selectAll()
                            .build();

                    PluginEditText input = view.requireViewById("input");
                    input.requestFocusAndShowIME();

                    // 显示对话框
                    pluginUI.buildDialog()
                            .setTitle("请输入内容")
                            .setView(view)
                            .setPositiveButton("{ok}", (dialog, which) -> {
                                String text = input.getText().toString();
                                preferences.edit().putString("custom_value", text).apply();
                                item.setSummary(getSummary(preferences));
                            })
                            .setNegativeButton("{cancel}", null)
                            .show();
                });
    }

    private String getSummary(SharedPreferences preferences) {
        String value = preferences.getString("custom_value", null);
        return value == null || value.isEmpty() ? "点击输入" : "当前值:" + value;
    }
}

# 输入校验

public class ValidationPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("输入校验示例");

        // 端口号校验
        builder.addInput("服务器端口", "server_port")
                .inputType(InputType.TYPE_CLASS_NUMBER)
                .defaultValue("8080")
                .validator(value -> {
                    if (value.isEmpty()) {
                        return "端口号不能为空";
                    }
                    try {
                        int port = Integer.parseInt(value);
                        if (port < 1 || port > 65535) {
                            return "端口号范围:1-65535";
                        }
                        return null;
                    } catch (NumberFormatException e) {
                        return "请输入有效的数字";
                    }
                });

        // URL 校验
        builder.addInput("API 地址", "api_url")
                .defaultValue("https://api.example.com")
                .valueAsSummary()
                .validator(value -> {
                    if (value.isEmpty()) {
                        return "地址不能为空";
                    }
                    if (!value.startsWith("http://") && !value.startsWith("https://")) {
                        return "地址必须以 http:// 或 https:// 开头";
                    }
                    return null;
                });
    }
}

# 点击拦截

public class InterceptPreference implements PluginPreference {
    @Override
    public void onBuild(PluginContext context, Builder builder) {
        builder.title("点击拦截示例");

        SharedPreferences preferences = context.getPreferences();

        // 拦截开关点击,显示确认对话框
        builder.addSwitch("重要选项", "important_option")
                .defaultValue(false)
                .interceptClick((pluginUI, preferenceItem) -> {
                    boolean currentValue = preferences.getBoolean("important_option", false);
                    String action = currentValue ? "关闭" : "开启";

                    pluginUI.buildDialog()
                            .setTitle("确认操作")
                            .setMessage("确定要" + action + "此选项吗?")
                            .setPositiveButton("{ok}", (dialog, which) -> {
                                preferences.edit()
                                        .putBoolean("important_option", !currentValue)
                                        .apply();
                                preferenceItem.getPreferenceScreen().recreate();
                            })
                            .setNegativeButton("{cancel}", null)
                            .show();
                    return true; // 拦截默认行为
                });

        // 拦截列表点击,在选择前执行检查
        builder.addList("网络模式", "network_mode")
                .defaultValue("auto")
                .addItem("自动", "auto")
                .addItem("仅WiFi", "wifi")
                .addItem("仅移动数据", "mobile")
                .interceptClick((pluginUI, preferenceItem) -> {
                    if (!isNetworkAvailable()) {
                        pluginUI.toast("当前无网络连接");
                        return true; // 拦截
                    }
                    return false; // 继续执行默认行为
                });
    }

    private boolean isNetworkAvailable() {
        // 网络检查逻辑
        return true;
    }
}

# 相关接口