Hi,
I’ve been writing a UI Framework library to handle common functionality such as navigation, history, transitions, modal windows etc. When I transition between different UI “screens” I wanted to be able to prevent the interaction of all child components of a given VisualElement. Similar to the functionality of a CanvasGroup with blocksRaycasts set to false.
I’ve tried SetEnabled(false), on the parent VisualElement, which does prevent interaction, however, it also greys out any interactive elements, similar to the interactable property of a CanvasGroup.
So far the only potential solution I have found is to iterate over the entire hierarchy of a VisualElement, cache all child elements that have their PickingMode property set to Position, temporarily set this property to Ignore and then when I want to re-enable the interactive of these elements iterate back over the cache and set it back to Position.
While this would work in some cases, it feels a little heavy handed, also this would become somewhat laborious when having to resolve dynamically populating the contents of VisualElement while its interaction should be disabled.
I am hoping that there is a simpler solution that I have just not found yet.
Any advice or suggestions would be greatly appreciated.
Thanks,
Luke.
For reference the current code I have implemented is as follows:
IterateHierarchy extension method:
public static void IterateHierarchy(this VisualElement visualElement, Action<VisualElement> action)
{
Stack<VisualElement> stack = new Stack<VisualElement>();
stack.Push(visualElement);
while (stack.Count > 0)
{
VisualElement currentElement = stack.Pop();
for (int i = 0; i < currentElement.hierarchy.childCount; i++)
{
VisualElement child = currentElement.hierarchy.ElementAt(i);
stack.Push(child);
action.Invoke(child);
}
}
}
SetInteractable function
protected void SetInteractable(VisualElement visualElement, bool interactable)
{
visualElement.pickingMode = interactable ? PickingMode.Position : PickingMode.Ignore;
visualElement.IterateHierarchy(delegate (VisualElement v)
{
v.pickingMode = interactable ? PickingMode.Position : PickingMode.Ignore;
});
}
This greying out is done with a general USS pseudo style, like all the styles that default Unity visual elements come with.
You can make a selector like :root:disabled
to change how they look when disabled, such as making them not change at all.
So follow up, when you disable something it gets the .unity-disabled
class added to it. And I’m pretty certain the only thing it does is change the opacity to 0.5. So you can just do this to override that behaviour:
.unity-disabled {
opacity: 1;
}
3 Likes