Releases reusable resources associated with this element and makes the element unusable.
The element must not be part of a hierarchy nor have any children, otherwise an InvalidOperationException is thrown.
Calling this method makes the element unusable. Only call it when the element is no longer needed.
Exceptions are thrown if you modify the element or add it again.
By default, a VisualElement releases its reusable resources only when it is garbage collected.
Calling this method explicitly releases those resources earlier so the system can immediately reuse them when creating new elements, reducing memory usage.
In most cases, it is more convenient to use VisualElement.Clear on a root element
which will recursively remove all its descendants and call ReleaseResources on each of them.
The following example shows how to release elements when implementing object pooling:
using UnityEngine; using UnityEngine.UIElements; using UnityEditor; using UnityEngine.Pool;
public class VisualElementPoolExampleWindow : EditorWindow { private ObjectPool<VisualElement> m_Pool;
[MenuItem("Window/Visual Element Pool")] public static void ShowWindow() { GetWindow<VisualElementPoolExampleWindow>("Visual Element Pool Example"); }
public void CreateGUI() { // Initialize the pool m_Pool = new ObjectPool<VisualElement>( createFunc: CreatePooledElement, actionOnGet: OnGetFromPool, actionOnRelease: null, actionOnDestroy: OnDestroyPooledElement, collectionCheck: true, defaultCapacity: 10, maxSize: 100 );
// Root element has PickingMode.Ignore by default. rootVisualElement.pickingMode = PickingMode.Position; rootVisualElement.RegisterCallback<ClickEvent>(OnClick);
// Add some instructions. var label = new Label("Click anywhere to spawn elements.\nClick on an element to return it to the pool."); label.pickingMode = PickingMode.Ignore; // Don't interfere with spawning. rootVisualElement.Add(label); }
private VisualElement CreatePooledElement() { var element = new VisualElement(); element.style.position = Position.Absolute; element.style.width = 50; element.style.height = 50; element.style.backgroundColor = new Color(Random.value, Random.value, Random.value); element.style.borderTopLeftRadius = 25; element.style.borderTopRightRadius = 25; element.style.borderBottomLeftRadius = 25; element.style.borderBottomRightRadius = 25;
// Stop click propagation so clicking on an element doesn't spawn a new one. element.RegisterCallback<ClickEvent>(OnElementClicked, TrickleDown.TrickleDown);
return element; }
private void OnGetFromPool(VisualElement element) { // Reset or configure the element when retrieved from the pool. element.style.backgroundColor = new Color(Random.value, Random.value, Random.value); }
private void OnDestroyPooledElement(VisualElement element) { // Cleanup when the element is destroyed (pool is disposed). element.UnregisterCallback<ClickEvent>(OnElementClicked, TrickleDown.TrickleDown);
// Make sure internal resources of the element are released immediately // because it is not added to the rootVisualElement of the window. element.ReleaseResources(); }
private void OnClick(ClickEvent evt) { // Spawn a new element at the click position. var element = m_Pool.Get(); element.style.left = evt.localPosition.x - 25; element.style.top = evt.localPosition.y - 25; rootVisualElement.Add(element); }
private void OnElementClicked(ClickEvent evt) { // Return element to pool when clicked. var element = evt.currentTarget as VisualElement; if (element != null) { element.RemoveFromHierarchy(); m_Pool.Release(element); }
// Stop propagation to prevent spawning a new element. evt.StopPropagation(); }
public void OnDestroy() { // Release any child element not currently in the pool. rootVisualElement.Clear(VisualElementClearOptions.RecursiveReleaseResources);
// Dispose of the pool when the window is closed. m_Pool?.Dispose(); } }