Open Lx34r opened 3 days ago
方便分享以下你的 Unity 版本吗?
首先,我的测试结果:2019.4上,正常(2019本身不支持UI Toolkit)
2022.2上,手动ban掉UIToolkit后,IMGUI出现吃掉 Header 的情况,但没有出现空间间隔情况(截图可以看到对象是由IMGUI绘制的无误)。
实际上,Unity 在 2022.1
起,修改了内部 PropertyField
fallback drawer 的绘制逻辑,导致一直 fallback 时会将 decorator drawer 反复重绘。因此 SaintsField 的 SaintsProperyDrawer 有以下代码处理 decorator 重绘问题:
#if UNITY_2022_1_OR_NEWER
Type dec = fieldInfo.GetCustomAttributes<PropertyAttribute>(true)
.Select(propertyAttribute =>
{
// Debug.Log(propertyAttribute.GetType());
Type results = _propertyAttributeToDecoratorDrawers.TryGetValue(propertyAttribute.GetType(),
out IReadOnlyList<Type> eachDrawers)
? eachDrawers[0]
: null;
// Debug.Log($"Found {results}");
return results;
})
.FirstOrDefault(each => each?.IsSubclassOf(typeof(DecoratorDrawer)) ?? false);
if (dec != null && ImGuiRemoveDecDraw(position, property, label))
{
return;
}
#endif
我先查一下 IMGUI 吃 Header 的问题。空白间隔的问题,需要你提供以下Unity版本号(请给完整的版本号带f
,比如2022.2.0f1
,如果是中国特供版,会以c1
结尾: 2022.2.0f1c1
)
Update: 狗了…2022+上,UIToolkit需要用反射手动移除 decorator 否则会多次绘制;IMGUI则不应移除否则不会绘制…我他妈…
算了,也不是第一次被 Unity 坑了… 吃 decorator 的问题我想想办法…
感谢在台风天假期的耐心回复 :)
EditorVersion:2022.3.46f1 (8e9b8558c41a)
哈哈哈,能深深感受到你的无奈,毕竟这世界就是个巨大的草台班子。Unity团队不仅解决 bug report 慢,而且拖半年多 fixed 后告知 bugfixes are backported,尤其是引入 Job 后处理 Mesh 的各种问题,说的就是破破烂烂的2022+。
实际上,Unity 在
2022.1
起,修改了内部PropertyField
fallback drawer 的绘制逻辑,导致一直 fallback 时会将 decorator drawer 反复重绘。因此 SaintsField 的 SaintsProperyDrawer 有以下代码处理 decorator 重绘问题:#if UNITY_2022_1_OR_NEWER Type dec = fieldInfo.GetCustomAttributes<PropertyAttribute>(true) .Select(propertyAttribute => { // Debug.Log(propertyAttribute.GetType()); Type results = _propertyAttributeToDecoratorDrawers.TryGetValue(propertyAttribute.GetType(), out IReadOnlyList<Type> eachDrawers) ? eachDrawers[0] : null; // Debug.Log($"Found {results}"); return results; }) .FirstOrDefault(each => each?.IsSubclassOf(typeof(DecoratorDrawer)) ?? false); if (dec != null && ImGuiRemoveDecDraw(position, property, label)) { return; } #endif
关于 Infobox 这类装饰器属性的绘制,我看到#71是使用 IPlayaAttribute 在 AbsRenderer 里进行额外处理的,为什么不考虑包装一个继承自 DecoratorDrawer 的类(比如 SaintsDecoratorDrawer)替代 SaintsPropertyDrawer 来绘制 Infobox 避免将其反复应用到数组/列表的内容上,是有什么考量么?
继承自 DecoratorDrawer 的类(比如 SaintsDecoratorDrawer)替代 SaintsPropertyDrawer 来绘制 Infobox 避免将其反复应用到数组/列表的内容上
拆分几个问题:
为什么不继承自 DecoratorDrawer
类
DecoratorDrawer 类,无法获取到 被装饰对象 的任何信息,导致所有 callback 都无法进行。这也是为什么 NaughtyAttribute无法支持 Conditional InfoBox 了,动态 InfoBox Content 也没法支持了。
这也是为什么开始有一个 SepTitle
(基于 DecoratorDrawer
),后面又做了一个 Separator
(基于 PropertyDrawer
),即使两者的功能非常相似。
Unity的PropertyDrawer带有 fieldInfo,而DecoratorDrawer并没有这个属性
避免将其反复应用到数组/列表的内容上的考量
实际上:
InfoBox
继承自 PropertyAttribute
,通过Unity的 PropertyDrawer
绘制,并且 会 应用到数组的元素上。PlayaInfoBox
带有 IPlayaAttribute
,通过 Unity 的 UnityEngine.Editor
绘制,并且 不会 应用到数组的元素上。这两者的考量,同样是因为 callback 的原因。 InfoBox
基于单个元素,因此可以基于元素值给出反馈:
[InfoBox("$" + nameof(ElementValidate), EMessageType.Error)] public string[] myValues;
// 这个特性我好像在文档中没好好写…
private string ElementValidate(string v, int index) => string.IsNullOrEmpty(v)? $"不允许空字符串,index位置: {index}": null;
而 PlayaInfoBox
的 callback,针对的是整个列表, callback 中获取的也是整个信息。
[PlayaInfoBox("$" + nameof(ElementValidateList), EMessageType.Error)] public string[] myArray;
private string ElementValidateList(string[] v) => v.Length < 5? $"数组长度必须>=5,当前长度: {v.Length}": null;
因此两者的应用场景虽然大部分相同,但对 array/list 时则完全不同了。
非常感谢耐心答疑,确实如此,我之前没有考虑到 callback 要拿列表的信息。
你好,方便的话请尝试以下 dev 分支,应该有解决这个问题。具体版本我…明儿再发 🥹
你好,方便的话请尝试以下 dev 分支,应该有解决这个问题。具体版本我…明儿再发 🥹
ok,等我拉一下测试看看。
更新:https://github.com/TylerTemp/SaintsField/commit/734818f2311a51206600608df841f67822ab2f1e 2022.3.46f1 (8e9b8558c41a) IMGUI 下已解决上述问题,等发版可以 close 这个 issue。
IMGUI 下,[Infobox] 无论是否是 below,绘制属性后均会有一段与 [Infobox] 同样高度的额外空白行,且不会正常绘制 [Header]
[IMGUI 高度错误,没有绘制 Header]
[UIToolkit 高度正确]
[Code]