Unity3D 游戏开发:背包数据界面 如何创建 ListView 的 Item Template模板 下(15)

1,216 阅读22分钟

一、脚本编程

1、用代码实现了一个Unity编辑器窗口(ItemEditor),用于管理游戏中的物品数据。它包含以下功能:

1. 通过Unity Editor窗口菜单栏创建了ItemEditor窗口。

2. 通过Visual Tree Asset加载了该窗口的布局和UI元素,包括一个ListView用于显示物品列表。

3. 通过一个SO (ScriptableObject) 文件来存储所有物品数据(ItemDataList_SO),同时通过ItemDetails类定义了物品的各种属性,比如id、名称、图标等。

4. 通过LoadDataBase()方法加载了物品数据列表,并使用EditorUtility.SetDirty(dataBase)方法标记数据发生了修改。

5. 通过GenerateListView()方法生成ListView,并将物品列表(itemList)绑定到ListView上。同时,该方法定义了如何显示每一个物品的UI,即如何对应ListView的items和UI模板(itemRowTemplate)。

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System;

public class ItemEditor : EditorWindow 
{
    private ItemDataList_SO dataBase;

    private List<ItemDetails> itemList  = new List<ItemDetails>();

    private VisualTreeAsset itemRowTemplate;
    private ListView itemlistView;

    [MenuItem("Lzj/ItemEditor")] 
    public static void ShowExample()
    {
        ItemEditor wnd = GetWindow<ItemEditor>();
        wnd.titleContent = new GUIContent("ItemEditor");
    }

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

       // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemEditor.uxml");
        VisualElement labelFromUXML = visualTree.Instantiate();
        root.Add(labelFromUXML);

        //拿到模板数据
        itemRowTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemRowTemplates.uxml");

        //变量赋值
        itemlistView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");
        //加载数据
        LoadDataBase();

        //生成ListView
        GenerateListView(); 

    }
    private void LoadDataBase()
    {
        var dataArray = AssetDatabase.FindAssets("ItemDataList_SO");

        if (dataArray.Length > 1)
        { 
            var path=AssetDatabase.GUIDToAssetPath(dataArray[0]);
            dataBase = AssetDatabase.LoadAssetAtPath(path, typeof(ItemDataList_SO)) as ItemDataList_SO ;
        }


        itemList = dataBase.itemDataList;

        EditorUtility.SetDirty(dataBase);

        //Debug.Log (itemList[0].itemID); 
    }
    private void GenerateListView()
    { 
        Func<VisualElement>makeItem=()=>itemRowTemplate.CloneTree();

        Action<VisualElement, int> bindItem = (e, i) =>
        {
            if (i < itemList.Count)
            {
                if (itemList[i].itemIcen!= null )
                    e.Q<VisualElement>("Icon").style.backgroundImage = itemList[i].itemIcen.texture;

                e.Q<Label>("Name").text = itemList[i]== null ? "No ITEM": itemList[i].itemName;
            }
        };
      //  itemlistView.fixedItemHeight=60;
        itemlistView.itemsSource = itemList;
        itemlistView.makeItem = makeItem;
        itemlistView.bindItem= bindItem;
    }
} 

image.png

image.png

将上图Item Template模板生成在ItemList中:

image.png

二、初步了解脚本编程以及API的调用

1、命名空间

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System;

1)、using UnityEditor;:这段代码引入了Unity编辑器的命名空间,用于在编辑器开发中使用Unity Editor API。

2)、using UnityEditor.UIElements;:这段代码引入了Unity编辑器和UIElements的命名空间,用于在编辑器中创建UI界面和交互式元素。

3)、using UnityEngine;:这段代码引入了Unity引擎的命名空间,包含了Unity中常用的类和函数。在脚本编写中,可以使用Unity引擎中的各种资源、组件等。

4)、using UnityEngine.UIElements;:这段代码引入了Unity UIElements的命名空间,用于在使用UIElements框架进行UI界面开发时调用相关的类和函数。

5)、using System.Collections.Generic;:这段代码引入了C#语言中的泛型集合命名空间,包含了常用的列表和字典等数据结构。

6)、using System;:这段代码引入了C#语言的系统命名空间,包含了一些常用的基础类型和常量。

2、声明变量,赋予控制权

private ItemDataList\_SO dataBase;
private List<ItemDetails> itemList  = new List<ItemDetails>();
private VisualTreeAsset itemRowTemplate;
private ListView itemlistView;

1)、private ItemDataList_SO dataBase:

C#中的私有变量声明,变量名为dataBase,类型为ItemDataList_SO是一个自定义的ScriptableObject脚本类型。在Unity中,ScriptableObject是一种可编写、可重用的数据对象,它们允许您在游戏运行时创建和修改数据,而无需从代码中硬编码数据项。通过使用ScriptableObject,您可以将数据项从游戏对象中分离出来,从而更轻松地管理和编辑它们。 通常,ScriptableObject会被用作某个编辑器工具或系统的配置信息、设置变量或其他需要预存数据的类型上。

回到这段代码,ItemDataList_SO类型被用作dataBase私有变量的类型。这可能意味着该变量在某些编辑器工具或系统中扮演着配置或预设数据的角色,可以在编辑器中进行配置和修改。同时,由于该变量为私有变量,只能在当前类内部被访问和使用,保证了其封装性和安全性。

2)、创建ItemDetails列表的List列表

private List<ItemDetails>itemList=new List<ItemDetails>()

这是一个C#中的私有变量声明,该变量名为itemList,类型为List<ItemDetails>,并使用了C#的泛型特性。该行代码声明了一个List<ItemDetails>类型的私有变量itemList,用于存储一组ItemDetails类型的对象。

List<ItemDetails>是一个泛型集合类,用于存储一组相同类型的对象。在此处,List<ItemDetails>被用来存储名为ItemDetails\的自定义结构体类型的对象。结构体类型通常用来封装数据,表示某个特定实体的属性和方法等信息。

在 C# 中,new 是一种实例化对象的方式。它可以用于创建一个新对象,然后返回其引用。在这里,new List<ItemDetails>() 表示创建了一个空的 List<ItemDetails> 对象,并将其引用赋值给了变量 itemList

List<ItemDetails> 是一个类,所以必须使用 new 关键字来创建一个新的对象。这个对象是列表类型,即内部包含多个 ItemDetails 类型的对象,可以通过 Add 方法添加新元素,或是通过 Remove 方法移除指定元素。每次创建一个新窗口时,都需要重新加载并创建一个新的 itemList 对象,并用它来更新列表控件的数据源。

3)、拿到Item Template模板的控制权和ListView列表的控制权:

        private VisualTreeAsset itemRowTemplate;//Item Template模板

        private ListView itemlistView;//利用Item Template模板的显示列表

3、创建窗口显示

        [MenuItem("Lzj/ItemEditor")] 
        public static void ShowExample()
        {
            ItemEditor wnd = GetWindow<ItemEditor>();
            wnd.titleContent = new GUIContent("ItemEditor");
        }

1)、[MenuItem("Lzj/ItemEditor")]

这段代码创建了一个菜单项,用于在Unity编辑器的顶部菜单中添加一个名为 Lzj 的菜单,再在 Lzj 菜单下添加一个名为 ItemEditor 的子菜单。点击该子菜单时可以触发相应的事件或打开相关的窗口。

2)、ItemEditor wnd = GetWindow <ItemEditor>():

调用了GetWindow<ItemEditor>()方法创建了一个名为wnd的新窗口,并将其赋值给本地变量wnd。然后,通过设置wnd.titleContent属性,将窗口的标题显示为"ItemEditor"

在Unity编辑器扩展中,使用GetWindow<T>()方法可以创建一个指定类型(T)的窗口。通过该方法,开发者可以在自己的编辑器工具或系统中创建自定义的窗口,并在其中添加自己需要的UI元素和功能。其中,泛型参数T指定了窗口对应的类或脚本类型。

在此例中,通过GetWindow<ItemEditor>()方法创建了一个名为ItemEditor的窗口,并将其赋值给wnd本地变量。

3)、 wnd.titleContent = new GUIContent("ItemEditor"):

设置wnd.titleContent属性,将窗口的标题显示为"ItemEditor"。其中,wnd 是创建的窗口实例,titleContent 属性用于设置窗口的标题内容。利用 GUIContent 类型的构造函数可以将字符串 ItemEditor"换成 GUIContent 类型的对象,并赋值给 titleContent 属性。

4、创建的窗口中添加GUI元素

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

       // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemEditor.uxml");
        VisualElement labelFromUXML = visualTree.Instantiate();
        root.Add(labelFromUXML);

        //拿到模板数据
        itemRowTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemRowTemplates.uxml");

        //变量赋值
        itemlistView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");
        //加载数据
        LoadDataBase();

        //生成ListView
        GenerateListView(); 
    }

1)、public void CreateGUI(){}:

这是一个公共方法,名为CreateGUI()。在该方法内部,首先获取了当前窗口的根视图(rootVisualElement)。用于在创建的窗口中添加GUI元素和界面布局。CreateGUI 方法在窗口初始化时会被调用,可以在该方法中添加各种UI元素,如按钮、文本框、下拉菜单等。用户可以在该方法中进行UI定制化操作,以满足自己项目的需求。

2)、isualElement root = rootVisualElement;:

  • 这段代码定义了一个名为 root 的 VisualElement 类型变量,并将根视图(rootVisualElement)赋值给它。在 Unity 中,窗口中的所有UI元素都是以 VisualElement 为单位,通过构建 VisualElement 树形结构来构建窗口界面布局。rootVisualElement 是窗口中默认最顶层的 VisualElement,通过将其赋值给变量 root,可以方便地在该窗口的上下文中添加其他 VisualElement 元素。

  • 根视图是窗口的最顶层UI元素,它是一个 VisualElement 类型对象,在 Unity 中用于表示当前窗口中的整个UI元素树形结构。在添加UI元素时,常常需要将它们作为子元素添加到根视图上,从而实现组件的布局和排版。可以通过获取根视图对象来访问窗口中的所有UI元素,对其进行定位、缩放、旋转等操作。在Unity中,可以通过 rootVisualElement 属性获取根视图对象。

3)、visualTree = AssetDatabase.LoadAssetAtPath<isualTreeAsset>Assets/Editor/UI Builder/ItemEditor.uxml");

这段代码使用 Unity 的 AssetDatabase 类加载了名为 "ItemEditor.uxml" 的 Visual Tree Asset(UI布局信息文件)。具体来说,代码中使用AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(path)方法从指定路径("Assets/Editor/UI Builder/ItemEditor.uxml")加载一个 isualTreeAsset 型的对象,并将其赋值给 visualTree 变量。通过加载 UXML 文件,可以快速构建复杂的UI界面布局,实现可视化设计。

4)、VisualElement labelFromUXML = visualTree.Instantiate();

这段代码使用 visualTree 对象(即上一个问题中加载的 ItemEditor.uxml 文件)来创建一个名为 labelFromUXMLVisualElement 实例。具体来说,代码中使用 Visual Tree Asset 的 Instantiate 方法实例化了 visualTree 中定义的UI元素,并将其赋值给 labelFromUXML 变量。通过实例化 Visual Element,可以将XML布局文件中定义的各种UI元素转换成实际运行时的对象,以便在代码中对它们进行进一步操作和控制。

visualTree.Instantiate()方法实例化了一个新的视图元素labelFromUXML

5)、root.Add(labelFromUXML):

这段代码将创建的VisualElement (即 labelFromUXML) 添加到根视图 root 中,以便显示在窗口中。具体来说,代码调用了 root 对象的 Add 方法,将 labelFromUXML 作为参数传入,实现了将 labelFromUXML 添加为根视图的子元素的操作。通过将 VisualElement添加到根视图中,可以在窗口中显示和管理该元素,并与窗口中的其他 UI 元素进行交互。

6)、 itemRowTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemRowTemplates.uxml");

加载了另一个UXML文件,存储了ListView中的每个子项模板。

这段代码使用 Unity 的 AssetDatabase 类加载了名为 "ItemRowTemplates.uxml" 的 Visual Tree Asset(UI布局信息文件)。具体来说,代码中使用LoadAssetAtPath方法从指定路径("Assets/Editor/UI Builder/ItemRowTemplates.uxml")加载一个VisualTreeAsset类型的对象,并将其赋值给 itemRowTemplate 变量。该 UXML 文件定义了用于显示列表项的UI元素布局模板

7)、itemlistView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");

通过root.Q<VisualElement>("ItemList").Q<ListView>("ListView")找到了名为"ItemList"的 VisualElement 元素,并找到其名为"ListView"的ListView子元素,并将元素赋予变量itemlistView

8)、LoadDataBase();

通过调用LoadDataBase()方法加载数据

9)、GenerateListView();

通过GenerateListView()方法生成ListView的子项以显示到视图中。

总而言之,该方法主要负责创建自定义窗口及视图,并将其添加到根视图中;加载数据;生成 ListView 子项等操作。

5、加载名为 "ItemDataList_SO" 的资源,并将数据存储到 itemList 字段中

    private void LoadDataBase()
    {
        var dataArray = AssetDatabase.FindAssets("ItemDataList_SO");

        if (dataArray.Length > 1)
        { 
            var path=AssetDatabase.GUIDToAssetPath(dataArray[0]);
            dataBase = AssetDatabase.LoadAssetAtPath(path, typeof(ItemDataList_SO)) as ItemDataList_SO ;
        }

        itemList = dataBase.itemDataList;

        EditorUtility.SetDirty(dataBase);

    }

这段代码的作用是加载项目中名为 "ItemDataList_SO" 的资源,并将其中的数据存储到 itemList 字段中。

首先,在该方法中调用 AssetDatabase.FindAssets("ItemDataList_SO") 方法查找名为 "ItemDataList_SO" 的资源,并将返回的所有匹配的资源 GUID 存储在 dataArray 数组中。然后,通过检查 dataArray 数组的长度是否大于 1 来确保只有一个匹配的资源,若不止一个资源,则选择第一个匹配的资源。接着,使用 AssetDatabase.GUIDToAssetPath() 方法将所选资源的 GUID 转换为其在项目中的路径,并使用 AssetDatabase.LoadAssetAtPath() 方法加载该资源。此处需要注意的是,返回的资源类型必须指定为 ItemDataList_SO,以便正确地将其转换为该类型的对象。

加载完成后,通过访问 dataBase.itemDataList 字段,可以获得包含在资源中的 ItemData 数据列表。最后,调用 EditorUtility.SetDirty() 方法来通知 Unity 引擎该对象已被修改,需要进行保存。

因此,该段代码的作用是从项目中加载名为 "ItemDataList_SO" 的资源,并将其中的数据存储到 itemList 字段中,以便在之后的编辑器扩展(Editor Extensions)中使用。

1)、var dataArray = AssetDatabase.FindAssets("ItemDataList_SO");

这段代码的作用是在 Unity 项目中查找名为 "ItemDataList_SO" 的 ScriptableObject 资源,并返回它们的 GUID 列表。

它使用 Unity 的 AssetDatabase 类的静态方法 FindAssets 来查找项目中所有名称为 "ItemDataList_SO" 的 ScriptableObject 资源,并将它们的 GUID 存储在一个名为 dataArray 的字符串数组中。每个元素都包含一个匹配项的唯一标识符,也称为 GUID。

FindAssets 方法的参数是一个字符串类型的参数,它代表着要查找的资源的名称(不包括路径和扩展名)。在这个例子中,查找的资源名称是 "ItemDataList_SO",表示查找所有名字为 "ItemDataList_SO" 的 ScriptableObject 资源。

最终返回的是一个字符串类型的数组,其中封装了所有名为 "ItemDataList_SO" 的 ScriptableObject 资源的 GUID。

因此,该代码段的作用是查找项目中名为 "ItemDataList_SO" 的资源,并将其 GUID 存储在 dataArray 数组中,以便后续的操作。

2)、if (dataArray.Length > 1)

这段代码是一个条件语句,它的作用是检查 dataArray 数组的长度是否大于 1。

如果 dataArray 的长度大于 1,那么表示在项目中有多个名为 "ItemDataList_SO" 的资源。

3)、var path=AssetDatabase.GUIDToAssetPath(dataArray[0]);

作用是将 dataArray 数组中第一个匹配项的 GUID 转换为资源的路径。

使用 Unity 的 AssetDatabase 类的静态方法 GUIDToAssetPath 来将 dataArray 数组中第一个匹配项的 GUID(全局唯一标识符)转换为资源的路径。这个资源路径是相对于 Unity 项目的根目录的,可以被用于加载该资源或者在编辑器中访问。

4)、dataBase = AssetDatabase.LoadAssetAtPath(path, typeof(ItemDataList_SO)) as ItemDataList_SO ;

这段代码的作用是从指定路径(path 变量)加载资源,并将其转换为 ItemDataList_SO 类型的对象,然后存储到 dataBase 变量中。

具体地说,它使用 Unity 的 AssetDatabase 类的静态方法 LoadAssetAtPath 加载 path 变量所代表的路径上的资源,并且将其的类型转换为 ItemDataList_SO。在这个例子中,ItemDataList_SO 是一个 ScriptableObject 类型的对象,包含了游戏中的所有物品数据信息。

LoadAssetAtPath 方法返回一个 Object 类型的对象,需要使用强制类型转换转换为 ItemDataList_SO 类型的对象。因此,这里使用了 as ItemDataList_SO 来完成类型转换。

最终,加载的 ItemDataList_SO 对象被赋值给名为 dataBase 的变量,以便在后续步骤中使用它所包含的物品数据信息。

5)、itemList = dataBase.itemDataList;

这段代码的作用是将 dataBase 变量中所包含的物品数据信息存储到 itemList 变量中,以便在后续步骤中使用。

具体地说,dataBase 是一个 ItemDataList_SO 类型的对象,其中包含了游戏中所有物品的相关信息。通过访问 dataBase.itemDataList 属性,可以获取 ItemDataList_SO 对象中所包含的名为 itemDataList 的字段的值,该字段实际上是一个存储所有物品信息的列表。因此,该代码行的作用是将该列表存储到 itemList 变量中,以便在后续步骤中使用。

需要注意的是,itemList 变量的类型必须与 itemDataList 字段所存储的类型相同,这里 itemDataList 的类型是 List<ItemData>,因此 itemList 的类型也应该是 List<ItemData>

6)、 EditorUtility.SetDirty(dataBase);

这段代码的作用是标记 dataBase 对象为“已修改”,以便 Unity 在保存场景或项目时将其正确地保存到磁盘上。

具体地说,EditorUtility.SetDirty 是 Unity 的 EditorUtility 类的静态方法。它用于标记一个对象为“已修改”,通知 Unity 在保存时需要保存该对象的状态,否则会丢失所做的更改。

在这个例子中,dataBase 是一个 ItemDataList_SO类型的 ScriptableObject 对象,它包含了游戏中所有物品的相关信息。当进行对 dataBase 的编辑操作之后,需要使用 EditorUtility.SetDirty 方法来告诉 Unity 需要保存这些编辑更改,否则更改将不会被保存。

7、生成一个包含多个列表项的列表视图,显示游戏中的物品信息。

    private void GenerateListView()
    { 
        Func<VisualElement>makeItem=()=>itemRowTemplate.CloneTree();

        Action<VisualElement, int> bindItem = (e, i) =>
        {
            if (i < itemList.Count)
            {
                if (itemList[i].itemIcon!= null )
                    e.Q<VisualElement>("Icon").style.backgroundImage = itemList[i].itemIcon.texture;
                e.Q<Label>("Name").text = itemList[i]== null ? "No ITEM": itemList[i].itemName;
            }
        };
        itemlistView.fixedItemHeight=60;
        itemlistView.itemsSource = itemList;
        itemlistView.makeItem = makeItem;
        itemlistView.bindItem= bindItem;
    }

这是一个私有方法,名为GenerateListView()。在该方法中,定义了两个委托变量:makeItembindItem

makeItem委托使用 lambda 表达式定义了一个方法,该方法通过调用itemRowTemplate.CloneTree()方法克隆了名为"ItemRowTemplates"的UXML模板,并将其作为返回值。具体来说,该方法将用于在ListView控件中生成每个子项。

bindItem委托使用 lambda 表达式定义了另外一个方法,该方法接受两个参数:e表示当前需要绑定数据的可视元素;i表示当前子项所在的索引位置。在该委托中,首先检查itemList列表中是否存在当前索引位置的子项,如果存在则获取该子项的基本信息并将其应用到对应的UI元素中。具体来说,代码中使用Q方法获取了需要修改的UI元素,并将对应数据赋值给它们。

最后,通过为itemlistView对象的itemsSourcemakeItembindItem属性分别赋值,将数据源、生成子项和绑定子项的操作与ListView控件关联起来。这样就可以将数据显示到界面上了。注释掉了其中一行代码 // itemlistView.fixedItemHeight=60;,该代码可能用于设置子项高度,但被注释掉了。

1)、 Func<VisualElement>makeItem=()=>itemRowTemplate.CloneTree();

这段代码创建了一个 lambda 表达式,并将其赋值给局部变量 makeItem

lambda 表达式的定义为:() => itemRowTemplate.CloneTree(),其中 ()=> 是 lambda 表达式的符号,表示它是一个不带参数的函数。在该函数中,执行了 itemRowTemplate.CloneTree() 方法,该方法会克隆 itemRowTemplate 对象并返回新的对象。

  • Func<VisualElement> 是一个委托类型,表示返回一个 VisualElement 的方法。
  • makeItem 是一个 Func<VisualElement> 类型的变量名,用于存储一个方法。
  • () 表示该方法没有参数。
  • => 表示该方法的返回值为后面的表达式。
  • itemRowTemplate 表示一个 VisualElement 实例,通常是一个自定义的列表行模板。
  • .CloneTree() 是 VisualElement 的方法,用于复制当前 VisualElement 中所有的子元素及其属性,并返回其新的 VisualElement 实例。

因此,这段代码的作用是定义了一个名为 makeItem 的方法,该方法返回一个 VisualElement 实例。具体实现是将 itemRowTemplate 进行深拷贝并返回其新的 VisualElement 实例,适用于动态地创建列表项时使用。在 Unity 引擎中,通常使用 VisualElement 来表示界面上的元素,因此该方法的返回值可以被用于显示在列表中的某一项。

2)、Action<VisualElement, int> bindItem = (e, i) =>{}

这段代码创建了一个 lambda 表达式,并将其赋值给局部变量 bindItem

lambda 表达式的定义为:(e, i) => {},其中 (e, i) 是 lambda 表达式的参数列表,表示该函数接受两个参数:VisualElement 类型的 e 和 int 类型的 i。在 => 符号后面的空花括号中,可以编写需要执行的代码。

  • Action<VisualElement, int> 是一个委托类型的定义,用于定义一个函数签名,该函数有两个参数:一个是 VisualElement 类型的参数 e,另一个是 int 类型的参数 i。该委托没有返回值(void)。
  • bindItem 是定义的一个委托类型变量,用于存储符合上述委托类型定义的具体函数实现。
  • = 是一个赋值运算符,用于将右边的表达式的值赋给左边的变量。
  • (e, i) => {} 是一个 lambda 表达式,它可以理解为一个匿名函数,表示具体的函数实现。括号中的 e 和 i 分别对应了前面定义的委托类型中的两个参数,而花括号内部则是函数体,即具体要执行的代码。

3)、 if (i < itemList.Count)

  • if 是一个条件判断语句,用于根据条件的结果来执行不同的代码。
  • (i < itemList.Count) 是该语句的条件部分,它表达了一个条件:当前索引值 i 是否小于物品列表 itemList 的长度。
  • < 是一个比较运算符,用于比较两个数的大小关系。在这里,它用于比较 i 和 itemList.Count 的大小关系,如果 i 比 itemList.Count 小,则返回 true;否则返回 false
  • i 是表示索引值的变量名,通常用于循环遍历列表或数组等数据结构时使用。
  • itemList 是物品列表对象的名称,通常用于存储一组相同类型的物品数据。Count 是物品列表对象的属性,用于表示物品列表的长度。

因此,这段代码的作用是,判断当前要绑定数据的列表项是否超出了物品列表中的数据范围,如果超出了,则不再对该位置的列表项进行数据绑定,以避免出现越界访问错误。

4)、 e.Q<VisualElement>("Icon").style.backgroundImage = itemList[i].itemIcon.texture;

  • e 表示一个 VisualElement 实例,通常是列表中的一个元素。
  • Q<VisualElement>("Icon") 是 VisualElement 类型的扩展方法,用于查找当前 VisualElement 中名称为 "Icon" 的子元素,并返回其 VisualElement 实例。该方法返回值是一个 VisualElement 实例或 null。
  • .style 表示 VisualElement 的样式对象,用于设置该元素的样式属性。
  • .backgroundImage 是样式对象的一个属性,表示该元素的背景图片(Background Image)。
  • itemList 是一个物品列表对象,用于存储一组相同类型的物品数据,i 是当前的索引值。
  • itemList[i] 表示根据当前的索引值获取物品列表中特定位置的元素,它是一个具体的物品对象。
  • .itemIcon 表示物品对象的图标属性,它指向一个 Texture2D 对象,用于表示该物品的图标信息。
  • .texture 表示 Texture2D 对象的纹理数据,用于显示在该元素的背景上。

因此,这段代码的作用是,在当前列表项的 "Icon" 子元素中,设置该元素的背景图像为当前索引对应的物品对象的图标纹理数据,实现了对列表项中数据和 UI 元素的绑定操作。这个操作的实现基于 Unity 引擎中的 UI 渲染技术,可以将物品图标等数据信息显示在列表项中。

5)、e.Q<Label>("Name").text = itemList[i]== null ? "No ITEM": itemList[i].itemName;

  • Q<Label>("Name") 是 VisualElement 类型的扩展方法,用于查找当前 VisualElement 中名称为 "Name" 的子元素,并返回其 Label 实例。该方法返回值是一个 Label 实例或 null。
  • .text 是 Label 的属性,表示该元素的文本内容。
  • .itemName 表示物品对象的名称属性,用于表示该物品的名称信息。

因此,这段代码的作用是,在当前列表项的 "Name" 子元素中,设置该元素的文本内容为当前索引对应的物品对象的名称,实现了对列表项中数据和 UI 元素的绑定操作。如果当前索引对应的物品对象为空,则该元素的文本内容将被设置为 "No ITEM"。这个操作的实现基于 Unity 引擎中的 UI 渲染技术,可以将物品名称等数据信息显示在列表项中。

6)、itemlistView.fixedItemHeight=60;

  • itemlistView 表示一个 Unity 引擎中的 ScrollView 实例,通常用于在界面上显示一个滚动区域。
  • .fixedItemHeight 是 ScrollView 的属性之一,用于设置列表项的固定高度。

因此,这段代码的作用是设置 itemlistView 中的列表项固定高度为 60 像素。在 Unity 引擎中,ScrollView 组件通常被用于实现一些需要滚动功能的 UI 界面,而其中的列表控件则会需要设置列表项的高度。通过设置列表项的固定高度,可以使得列表更加美观和规整,并且减少列表因为高度不一而导致的滚动条的跳跃感。

7)、itemlistView.itemsSource = itemList;

  • itemlistView 表示一个 Unity 引擎中的 ScrollView 实例,通常用于在界面上显示一个滚动区域。
  • .itemsSource 是 ScrollView 的属性之一,用于设置列表的数据源。
  • itemList 是一个物品列表对象,用于存储一组相同类型的物品数据。

因此,这段代码的作用是将物品列表 itemList 赋值给 itemlistView 的数据源属性,从而将物品列表中的数据加载到列表控件中进行显示。在 Unity 引擎中,列表控件通常需要通过指定数据源的方式来实现数据绑定,以便从数据源中读取数据并显示在列表项中。该代码赋值操作可以将一个包含多个物品对象的列表与一个 UI 列表控件进行绑定,在每个列表项中显示物品对象的相关信息。

8)、itemlistView.makeItem = makeItem;

  • itemlistView 表示一个 Unity 引擎中的 ScrollView 实例,通常用于在界面上显示一个滚动区域。
  • .makeItem 是 ScrollView 的属性之一,用于设置创建列表项的委托函数。
  • makeItem 是一个 Func<VisualElement> 类型的变量名,用于存储一个方法,返回类型是 VisualElement。

因此,这段代码的作用是将创建列表项的委托函数 makeItem 赋值给 itemlistView 中的 .makeItem 属性,从而告诉 itemlistView 在需要创建新的列表项时使用哪个委托函数来进行创建。委托是 C# 编程语言中的一种重要机制,其本质是一种可以传递行为的类型,可以将一个方法作为一个参数或返回值来传递。由于列表控件通常需要动态地创建列表项,因此可以通过设置 makeItem 属性来指定创建列表项的委托函数。该代码将一个名为 makeItem 的方法赋值给了 itemlistView 中的 makeItem 属性,因此 itemlistView 在需要创建新的列表项时,会调用该方法来进行创建,并返回一个 VisualElement 对象作为列表项的实例。

9)、itemlistView.bindItem= bindItem;

  • itemlistView 表示一个 Unity 引擎中的 ScrollView 实例,通常用于在界面上显示一个滚动区域。
  • .bindItem 是 ScrollView 的属性之一,用于设置绑定列表项的委托函数。
  • bindItem 是一个 Func<VisualElement, int, bool> 类型的变量名,用于存储一个方法,接受两个参数:VisualElement 类型的对象和 int 类型的索引值,返回类型是 bool。

因此,这段代码的作用是将绑定列表项的委托函数 bindItem 赋值给 itemlistView 中的 .bindItem 属性,从而告诉 itemlistView 在需要绑定列表项时使用哪个委托函数来进行绑定。类似于 .makeItem 属性,.bindItem 属性也是一个委托函数,用于将数据源中的数据绑定到指定的列表项上,实现数据和 UI 界面的关联。该属性需要接受两个参数:VisualElement 类型的对象和 int 类型的索引值,分别表示当前要绑定的列表项实例和该项在数据源中的索引位置。通过设置 bindItem 属性,可以方便地实现列表项与数据的双向绑定,在数据源发生变化时自动更新列表项内容。

阅读更多作者文章:

用户界面(Editor)如何创建 ListView 的 Item Template 上(14)