Files
netease-modsdk-wiki/docs/mconline/90-知识库获奖教程/2-界面与交互/0-自定义一个UI控件(调色盘).md
boybook 760c2dd9ad 2.6
2025-12-01 20:59:16 +08:00

173 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 自定义一个UI控件调色盘
> 本篇教程获得第一期知识库必看教程奖。
>
> 获奖作者:红石公司。
先来看看代码部分和具体效果:
![img](./images/0_1.png)
![img](./images/0_2.png)
上图展示了简单的一行json配置即可实现一个自由调节的调色板控件其中包含滑动条、输入框、颜色选择器按钮等组合控件。
这是笔者做过最复杂的一个自定义控件,其他的还有: 数字输入框、虚拟摇杆、可拖动面板等。
任何你觉得以后可以用到的组合控件,都可以打包为自定义控件。
![img](./images/0_3.png)
![img](./images/0_4.png)
下面简单讲解一下实现方法。
## json部分
先建立一个控件库json文件方便以后直从库中继承。
1. 调色板左侧色盘部分采用了三张图片叠加第一层纯白、第二层是一个从左到右从透明到纯白的渐变图片第三层是一个从上到下从透明到纯黑的渐变图片。这里第三层的渐变使用gradient_renderer渲染器实现。我们调整第二层的颜色整个色盘就会按预想的变色。
![img](./images/0_5.png)
![img](./images/0_6.png)
![img](./images/0_7.png)
2. 颜色选择器就是图中色盘上的圆圈。这里整个色盘的父控件是一个input_button和button一样但是没有“default”、"pressed"等状态,是一个空白的按钮。
![img](./images/0_8.png)
选用按钮控件的目的是在脚本中监听move事件然后通过事件中的坐标改变选择器圆圈的位置调整颜色等。
3. 色相滑动条。
![img](./images/0_9.png)
就是这个东西简单继承了一个滑动条控件将背景和box改变一下样式。背景依旧采用gradient_renderer渲染器但是是一个stack_panel下排列的6个渐变色。其中最底层选用一个空图片控件原因是滑动条背景必须是一个图片否则游戏报错。
![img](./images/0_10.png)
4. 颜色数字输入框。
![img](./images/0_11.png)
简单堆叠三个输入框即可。
5. 颜色展示器。
![img](./images/0_12.png)
简单的一个图片控件。以上部分组合起来就是一个完整的调色板控件了,
![img](./images/0_13.png)
我们在自己的json文件中继承调色板控件。
![img](./images/0_14.png)
## 脚本部分
1. 即装即用。
1. json部分为了实现继承调色板控件后无需多余配置无需使用路径注册我们要实现一个“自动扫描整个界面中的调色板控件”的功能。且需要兼容同时存在多个调色板。 但是我们无法真正的添加一个控件属性。
我的解决方案是,在调色板控件下增加一个子控件,控件名字是一个标签。我们在脚本中遍历路径,找到标签后往上退一个路径,就是调色板的路径。
![img](./images/0_15.png)
如图所示,控件名=标签+自定义名,脚本中依靠“标签名“确认是否为调色板控件,使用“自定义名”区分同时存在的多个色板。
![img](./images/0_16.png)
如图所示在实际使用过程中配置custom_ui_name变量即可。
2. 脚本部分使用GetChildrenName获取子控件名字并一层层递归下去知道找到标签为止。这部分不过多赘述各位多多实践自己做出来才是最好的。不是特别大规模的UI界面整个扫描过程不会超过20ms基本无法察觉。但是界面中如果存在grid最好需要过滤下。当然标签的使用可以做到即装即用但是也会造成额外的性能消耗如果可以接受手动输入路径注册那么就不需要使用标签来获取路径了。
2. 前置。
我们要将逻辑代码封装在前置中我们的UI类需要继承这个前置。如果你已经有其他的前置多继承可能造成冲突可以再加一层继承来写你的逻辑代码。如果追求代码纯净不想用前置像我一样可以使用如下方式
![img](./images/0_17.png)
新建一个控件类传入UI实例控件路径等。在这个类中编写你的逻辑代码。
3. 装饰生命周期函数。如果你的控件需要用到生命周期函数如CreateUpdate等你需要在自己的UI类中主动调用。
即装即用又不想主动调用,那怎么办呢?
答案是装饰器将UI的生命周期函数装饰一下那么如何在自定义类中装饰UI的函数呢毕竟我不想动UI的任何代码也不想写@符号
可以采用如下方式:
![img](./images/0_18.png)
这样在调用a_name方法时就会自动调用下b_name方法。
在自定义类`__init__`时,使用此方法装饰一下必要的生命周期函数。
4. 动态创建绑定。调色板需要用到 **Slider****TextEditBox** 控件这两个控件是需要进行绑定的。当然可以使用Update来实时检测但我并不想耗费这个性能。
动态创建绑定的应用范围非常广,之前没有人公布过方法,在此我公布一下。
![img](./images/0_19.png)
如图self.ui是一个UI实例将两个函数绑定到了实例上。和在UI类中进行绑定效果相同但是这个代码实际写在自定义类中`__init__`时调用。 **#RCM_SDK_PALETTE_EDIT_BOX** 和 **#RCM_SDK_PALETTE_SLIDER** 分别是UI中的文本框和滑动条绑定的变量。如果不懂绑定可以去观察下官方demo。
5. 现在我们已经集齐所有前置条件,是时候编写逻辑代码了。
1. 基础知识。整个调色板是HSB结构如图所示。
![img](./images/0_20.png)
H代表色相S代表饱和度B代表亮度。颜色输出、文本框显示都是用RGB标准那就需要堆HSB和RGB进行转换。这个大家可自行百度。
2. 色相滑动条。当色相滑动条滑动时滑块位置对应hsb中的H因此调整H后并转换为RGB更新色盘颜色、展示器颜色、文本框文字即可。
3. 颜色选择器。即左边的圈圈。由于色盘底是一个按钮我们注册按钮move事件在事件中根据手指坐标和相对位置计算出x轴和y轴的比例将比例限制在0-1内再设置圆圈位置更新展示器颜色和文本框文字。
4. 文本框调色。文本框输入数字时将数字限制在0-255内int格式。然后转为hsb设置滑动条位置、选择器位置再更新色盘颜色、展示器颜色即可。
5. 颜色改变监听。自定义类中加入一个self.back变量传入你的回调函数。在上述进行任何改变颜色的操作后将颜色结果通知到回调函数即可。
6. 接口拓展。GetColor、SetColor、GetVisible、SetVisible等。
## 示例结果
按I键打开和关闭界面。展示了两个互相独立的调色板并监听了颜色变化事件。
![img](./images/0_21.png)
**demo只简单展示了自定义控件的实现思路仅作为功能预览不具备实用性。还需要各位开发者根据自己的实际情况以及编程习惯开发自己的自定义控件。**
本人是编程新手,也是开发新手,教程如有什么纰漏,表述不当,还请大家指出改进。
若有哪里不明白的地方,可以在评论区提问,我会及时解答的。