WarningSome APIs might get changed in the future
You can use AbsRenderer to control how each field is rendered.
Example type:
public class MyMonoWithCustom : MonoBehaviour { public string myString; public bool toggle; public string input; public int myInt; }
Now let's make a toggleable input
using System.Collections.Generic; using SaintsField.Editor.Playa; using SaintsField.Editor.Playa.Renderer.BaseRenderer; using UnityEditor; using UnityEngine.UIElements; [CustomEditor(typeof(MyMonoWithCustom), true)] public class MyMonoWithCustomEditor : SaintsField.Editor.SaintsEditor { public override IEnumerable<IReadOnlyList<SaintsFieldWithRenderer>> MakeRenderer( SerializedObject so, SaintsFieldWithInfo fieldWithInfo) { if (fieldWithInfo.FieldInfo?.Name == nameof(MyMonoWithCustom.toggle)) { yield break; // returns nothing to show nothing } if (fieldWithInfo.FieldInfo?.Name == nameof(MyMonoWithCustom.input)) { yield return WrapAroundSaintsRenderer( new[] { new ToggleInputRenderer(so, fieldWithInfo) }, so, fieldWithInfo); yield break; } // default rendering foreach (IReadOnlyList<SaintsFieldWithRenderer> defaultRenderer in base.MakeRenderer(so, fieldWithInfo)) { yield return defaultRenderer; } } } public class ToggleInputRenderer: AbsRenderer { private readonly SerializedObject _serializedObject; public ToggleInputRenderer(SerializedObject serializedObject, SaintsFieldWithInfo fieldWithInfo) : base(serializedObject, fieldWithInfo) { _serializedObject = serializedObject; } public override void OnDestroy() { } public override void OnSearchField(string searchString) { } protected override void RenderTargetIMGUI(float width, PreCheckResult preCheckResult) { } protected override float GetFieldHeightIMGUI(float width, PreCheckResult preCheckResult) { return 0; } protected override void RenderPositionTargetIMGUI(Rect position, PreCheckResult preCheckResult) { } protected override (VisualElement target, bool needUpdate) CreateTargetUIToolkit(VisualElement container) { VisualElement root = new VisualElement { style = { flexDirection = FlexDirection.Row, }, }; Toggle toggle = new Toggle("Input") { bindingPath = _serializedObject.FindProperty("toggle").propertyPath, }; toggle.AddToClassList(Toggle.alignedFieldUssClassName); root.Add(toggle); TextField input = new TextField { bindingPath = _serializedObject.FindProperty("input").propertyPath, style = { flexGrow = 1, flexShrink = 1, }, }; root.Add(input); return (root, true); } protected override PreCheckResult OnUpdateUIToolKit(VisualElement root) { // If needUpdate=true, this function is called every 0.1s. You can do some ticking update here. TextField textField = root.Q<TextField>(); textField.SetEnabled(_serializedObject.FindProperty("toggle").boolValue); // return the required value return base.OnUpdateUIToolKit(root); } }
WrapAroundSaintsRenderer means the supplied renderers handle the target field. Saints Field keeps the
field's other attributes in their declared order and does not create its default target renderer. Put multiple
custom renderers in the same array when they jointly render one target field. yield break hides the whole
member, including its surrounding renderers. Delegate to base.MakeRenderer to keep the complete default
behavior.