Я пытаюсь расширить TextMeshProUI с помощью специальной реализации. Я расширил им редактор, чтобы можно было отслеживать некоторые изменения.
public class LocalizedTMP_UGUI : TextMeshProUGUI
{
// Stripped code
[SerializeField] private List<LocArgument> m_arguments;
public void SetLocalizedText()
{
text = m_localizer.GetLocalization(m_localizationKey, m_arguments);
ForceMeshUpdate();
}
}
[Serializable]
public class LocArgument
{
public string name;
public string value;
public LocArgument(string name, string value)
{
this.name = name;
this.value = value;
}
}
И что касается редакторской части:
[CustomEditor(typeof(LocalizedTMP_UGUI))]
[CanEditMultipleObjects]
public class LocalizedTMP_UGUI_Editor : TMP_EditorPanelUI, ITMPEditor
{
private SerializedProperty m_arguments;
private string [] m_languages;
private int m_languageIndex = 0;
private ILocalization m_localizer;
// removed OnEnable
public override void OnInspectorGUI()
{
serializedObject.Update();
int languageIndex = EditorGUILayout.Popup(m_languageIndex, m_languages);
if (languageIndex != m_languageIndex)
{
m_localizer.SetWithLocale(m_languages[languageIndex]);
SetText();
m_languageIndex = languageIndex;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_arguments);
if (EditorGUI.EndChangeCheck())
{
SetText();
}
serializedObject.ApplyModifiedProperties();
base.OnInspectorGUI();
}
public void SetText()
{
LocalizedTMP_UGUI targetComp = (LocalizedTMP_UGUI)target;
targetComp.SetLocalizedText();
Repaint();
}
}
Когда я переключаю настройку в EditorGUILayout.Popup, текст обновляется. Но если я изменю содержимое списка аргументов (поля значения), это не повлияет ни на отображаемый текст в сцене, ни на текстовое поле компонента. Хотя при взаимодействии с инспектором (например, сворачивании/развертывании списка) он обновляется и отображается правильно.
Я заметил, что при отладке метода SetLocalizedText текст назначается с задержкой в одну букву. Итак, если я начну вводить «Привет», то при вводе H будет отображаться «», затем при следующем вводе e будет отображаться «H», затем «He» при вводе l и так далее. И хотя свойство text установлено, оно не обновит текстовое поле в инспекторе, пока не поработает с компонентом.
Спасибо за это, это направило меня в правильном направлении!
У меня было две проблемы: во-первых, судя по комментариям, я устанавливал текстовое поле, хотя оно должно быть сериализованным свойством.
private SerializedProperty m_text;
protected override void OnEnable()
{
m_text = serializedObject.FindProperty("m_text");
}
public void SetText()
{
LocalizedTMP_UGUI targetComp = (LocalizedTMP_UGUI)target;
m_text.stringValue = m_localizer.GetLocalization(targetComp.LocalizationKey, targetComp.Arguments.ToList());
serializedObject.ApplyModifiedProperties();
}
Дополнительная проблема возникла в следующем случае: проверка возвращает true, но сериализованный объект все еще необходимо обновить.
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
SetText();
}
ApplyModifiedProperty обычно размещается в конце OnInspectorGUI, но в этом случае он необходим в проверке для обновления свойства перед его использованием.
когда вы изменяете target
, вам нужно будет использовать либо EditorUtility.SetDirty , чтобы пометить этот ресурс как грязный, чтобы ваши изменения действительно были сохранены при нажатии ctrl + s
... или даже Undo.RecordObject , чтобы правильно поддержка отмены/повтора, а также, если это потенциально префаб, даже PrefabUtility.RecordPrefabInstancePropertyModifications
=> вы почти всегда предпочитаете использовать SerialzedProperty
и SerializedObject
вместо того, чтобы иметь дело с этими низкоуровневыми инструментами ;)
Вероятно, это связано с сочетанием прямого доступа с доступом к сериализованным объектам. SerializedObject — это снимок объекта с использованием отражения, установленный при вызове Update. Все, что вы меняете вручную (без использования методов сериализованного объекта) после вызова обновления, не находится в сериализованном объекте. Таким образом, установка текста непосредственно в цели не отражается на сериализованном объекте. Вы можете: изменить место вызова обновления, установить текст с помощью свойств сериализованного объекта или сделать все это путем назначения вручную.