I can’t find my way into making an Item for a ListView using a uxml template that I loaded from the Resources.
all examples I find build the item via code, but using uxml allows me to make a complex cell easily, it will have many labels, few buttons, and probably more.
I tried CloneTree() and Instantiate() but they are not working…
void MakeTempListContent()
{
ListView listView = rootVisualElement.Q<ListView>("ListView");
VisualTreeAsset ListItem = Resources.Load<VisualTreeAsset>("ListItemTemplate");
const int itemCount = 30;
var items = new List<string>(itemCount);
for (int i = 1; i <= itemCount; i++)
items.Add(i.ToString());
listView.makeItem = () => ListItem.CloneTree(); // doesn't work, and ListItem.Instantiate() neither.
//listView.bindItem = (e, i) => (e as Label).text = items[i];
listView.onItemChosen += obj => Debug.Log(obj);
listView.onSelectionChanged += objects => Debug.Log(objects);
listView.itemsSource = items;
}
In order for this to work, the bindItem has to be defined. Also, the .uxml file for the ListView needs to define the view and entry height (–unity-item-height).
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
public class SampleListView : EditorWindow
{
[MenuItem("Window/UI Toolkit/SampleListView")]
public static void ShowExample()
{
SampleListView wnd = GetWindow<SampleListView>();
wnd.titleContent = new GUIContent("SampleListView");
}
public void CreateGUI()
{
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/Main.uxml");
VisualElement main = visualTree.Instantiate();
rootVisualElement.Add(main);
// Create some list of data, here simply numbers in interval [1, 1000]
const int itemCount = 1000;
var items = new List<string>(itemCount);
for (int i = 1; i <= itemCount; i++)
items.Add(i.ToString());
var listItem = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/SampleListView.uxml");
Func<VisualElement> makeItem = () => listItem.Instantiate();
Action<VisualElement, int> bindItem = (e, i) =>
{
var label = e.Q<Label>();
label.text = items[i];
var button = e.Q<Button>();
button.text = "Button " + items[i];
};
var listView = main.Q<ListView>();
listView.makeItem = makeItem;
listView.bindItem = bindItem;
listView.itemsSource = items;
listView.selectionType = SelectionType.Multiple;
}
}
This only works in the editor since AssetDatabase is in the Editor namespace.
For runtime use I tried Resources.Load(“myAsset”) which worked.
But I run into a small problem:
The Rootelement of myAsset.uxml is of type “Button”, but "item.Instantiate() only works for VisualElement.
is there a way to have Button as root element?
I don’t have a custom listview either what i meant is creating ui elements that are based on custom uxmls. I do this basically like in the examples posted here.
But insead of
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/Main.uxml");
I use
var visualTree = Resources.Load<VisualTreeAsset>("Assets/Editor/Main.uxml");
The problem of this method is, that unity creates a Wrapper VisualElement around the content of the uxml.
I have a Spawner with an Wave array, these waves also have some WaveTiming objects inside them.
I’d like to define and reuse the WaveEditor and WaveTimingEditor while having a ListView handling the waves at the SpawnerEditor level.
It’s very unclear to me how to make this work. I was expecting just creating the custom WaveEditor would change the rendering inside the ListView of the SpawnerEditor but it does not.
[CustomEditor(typeof(Wave))]
public class WaveEditor : Editor
{
public VisualTreeAsset tree;
public override VisualElement CreateInspectorGUI()
{
VisualElement customInspector = new VisualElement();
tree.CloneTree(customInspector);
return customInspector;
}
}
I have set the public tree variable to my UXMLWave file which just has MinMaxSlider, so I’d expect to see it instead of the default inspector for each item.
[CustomEditor(typeof(OffscreenSpawner))]
public class OffscreenSpawnerEditor : Editor
{
const string path = "Editors/OffscreenSpawner";
const string editorTemplateName = "offscreen-spawner-editor";
const string editorStyleName = "offscreen-spawner-editor-style";
const string waveEditorTemplateName = "UXMLWave";
public override VisualElement CreateInspectorGUI()
{
VisualElement customInspector = new VisualElement();
VisualTreeAsset editorTemplate = Resources.Load(GetPath(editorTemplateName)) as VisualTreeAsset;
editorTemplate.CloneTree(customInspector);
customInspector.styleSheets.Add(Resources.Load(GetPath(editorStyleName)) as StyleSheet);
return customInspector;
}
private string GetPath(string fileName)
{
return $"{path}/{fileName}";
}
}
And this one’s uxml only has a ListView that displays the waves array but I’m just seeing the default editor for my Wave items.
documentation and visual examples for ui toolkit, especially the ui builder which is a visual thing is not really given the examples it should have in the docs. And the generated uxml and tying that up in code to create lists etc is not great considering it’s been out so long