UI Toolkit系统学习

UI Toolkit
此文章用于学习UnityUI系统,手头的项目做完会来完善
官方文档
Unity上方菜单栏点击Window->UI Toolkit->Samples可以看UI Toolkit中的很多样例

使用 UI Toolkit 和 UI Builder 制作物品编辑器

在文件夹中右键->Create->UI Toolkit->Editor Window
出现以下窗口
在这里插入图片描述
输入名字创建窗口
文件夹中出现三个文件
在这里插入图片描述
从这步开始就能点击Unity上方菜单栏召唤自己写的Editor Window了

点击ItemEditor进入UIBuilder,用里面的工具创建需要的UI面板
在这里插入图片描述

创建 ListView 中的 ItemTemplate

再创建一个UIDocument,作为ItemList中每一个物体显示的模板
在这里插入图片描述

生成 ListView 列表

实现ItemTemplate读取数据库中物品数据并将其呈现在ListView上的方法

public class ItemEditor : EditorWindow
{
    private ItemDataList_SO dataBase;
    private List<ItemDetails> itemList = new List<ItemDetails>();
    private VisualTreeAsset itemRowTemplate;
    private ListView itemListView;
    
    [MenuItem("Editor/ItemEditor")]
    public static void ShowExample()
    {
        ItemEditor wnd = GetWindow<ItemEditor>();
        wnd.titleContent = new GUIContent("ItemEditor");
    }

    public void CreateGUI()
    {
       
        VisualElement root = rootVisualElement;
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UIBuilder/ItemEditor.uxml");
        VisualElement labelFromUXML = visualTree.Instantiate();
        root.Add(labelFromUXML);
        
        //拿到模板数据
        itemRowTemplate =
            AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UIBuilder/ItemRowTemplate.uxml");
        //变量赋值
        itemListView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");
        LoadDataBase();
        GenerateListView();
    }
    /// <summary>
    /// 从数据库中加载文件
    /// </summary>
    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.itemDetailsList;
        //如果不标记则无法保存数据
        EditorUtility.SetDirty(dataBase);
    }

    private void GenerateListView()
    {
        Func<VisualElement> makeItem = () => itemRowTemplate.CloneTree();//创建
        Action<VisualElement, int> bindItem = (e, i) =>
        {//在ItemTemplate上绑定数据
            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;
            }
        };
        //将ItemTemplate呈现在ListView里
        itemListView.fixedItemHeight = 60;
        itemListView.itemsSource = itemList;
        itemListView.makeItem = makeItem;
        itemListView.bindItem = bindItem;
    }
}

makeItem会在每次添加新物品时调用——在数据绘制到窗口时会根据数据的数目逐一增加一个Item的时候
bindItem每个窗口显示的具体内容
itemsSource对应itemList里面的每一个数据

绑定 Editor Window 中的参数变量,实现 ListView 添加删除同步信息功能

实现在右侧面板中显示物体对应的信息

public class ItemEditor : EditorWindow
{
    private ItemDataList_SO dataBase;
    private List<ItemDetails> itemList = new List<ItemDetails>();
    private VisualTreeAsset itemRowTemplate;
    private ScrollView itemDetailsSection;
    private ItemDetails activeItem;

    //默认预览图片
    private Sprite defaultIcon;

    private VisualElement iconPreview;
    //获得VisualElement
    private ListView itemListView;

    [MenuItem("M STUDIO/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;

        // VisualElements objects can contain other VisualElement following a tree hierarchy.
        // VisualElement label = new Label("Hello World! From C#");
        // root.Add(label);

        // 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/ItemRowTemplate.uxml");

        //拿默认Icon图片
        defaultIcon = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/M Studio/Art/Items/Icons/icon_M.png");

        //变量赋值
        itemListView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");
        itemDetailsSection = root.Q<ScrollView>("ItemDetails");
        iconPreview = itemDetailsSection.Q<VisualElement>("Icon");


        //获得按键
        root.Q<Button>("AddButton").clicked += OnAddItemClicked;
        root.Q<Button>("DeleteButton").clicked += OnDeleteClicked;
        //加载数据
        LoadDataBase();

        //生成ListView
        GenerateListView();
    }

    #region 按键事件
    private void OnDeleteClicked()
    {
        itemList.Remove(activeItem);
        itemListView.Rebuild();
        itemDetailsSection.visible = false;
    }

    private void OnAddItemClicked()
    {
        ItemDetails newItem = new ItemDetails();
        newItem.itemName = "NEW ITEM";
        newItem.itemID = 1001 + itemList.Count;
        itemList.Add(newItem);
        itemListView.Rebuild();
    }
    #endregion

    private void LoadDataBase()
    {
        var dataArray = AssetDatabase.FindAssets("ItemDataList_SO");
        //var dataArray = AssetDatabase.FindAssets("t:ItemDataList_SO");  //不同版本写法不一样
        //if (dataArray.Length >= 1)    //不同版本写法不同
        if (dataArray.Length > 1)
        {
            var path = AssetDatabase.GUIDToAssetPath(dataArray[0]);
            dataBase = AssetDatabase.LoadAssetAtPath(path, typeof(ItemDataList_SO)) as ItemDataList_SO;
        }

        itemList = dataBase.itemDetailsList;
        //如果不标记则无法保存数据
        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].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 = 50;  //根据需要高度调整数值
        itemListView.itemsSource = itemList;
        itemListView.makeItem = makeItem;
        itemListView.bindItem = bindItem;

        itemListView.onSelectionChange += OnListSelectionChange;

        //右侧信息面板不可见
        itemDetailsSection.visible = false;
    }

    private void OnListSelectionChange(IEnumerable<object> selectedItem)
    {
        activeItem = (ItemDetails)selectedItem.First();
        GetItemDetails();
        itemDetailsSection.visible = true;
    }

    private void GetItemDetails()
    {
        itemDetailsSection.MarkDirtyRepaint();

        itemDetailsSection.Q<IntegerField>("ItemID").value = activeItem.itemID;
        itemDetailsSection.Q<IntegerField>("ItemID").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemID = evt.newValue;
        });

        itemDetailsSection.Q<TextField>("ItemName").value = activeItem.itemName;
        itemDetailsSection.Q<TextField>("ItemName").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemName = evt.newValue;
            itemListView.Rebuild();
        });

        iconPreview.style.backgroundImage = activeItem.itemIcon == null ? defaultIcon.texture : activeItem.itemIcon.texture;
        itemDetailsSection.Q<ObjectField>("ItemIcon").value = activeItem.itemIcon;
        itemDetailsSection.Q<ObjectField>("ItemIcon").RegisterValueChangedCallback(evt =>
        {
            Sprite newIcon = evt.newValue as Sprite;
            activeItem.itemIcon = newIcon;

            iconPreview.style.backgroundImage = newIcon == null ? defaultIcon.texture : newIcon.texture;
            itemListView.Rebuild();
        });

        //其他所有变量的绑定
        itemDetailsSection.Q<ObjectField>("ItemSprite").value = activeItem.itemOnWorldSprite;
        itemDetailsSection.Q<ObjectField>("ItemSprite").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemOnWorldSprite = (Sprite)evt.newValue;
        });

        itemDetailsSection.Q<EnumField>("ItemType").Init(activeItem.itemType);
        itemDetailsSection.Q<EnumField>("ItemType").value = activeItem.itemType;
        itemDetailsSection.Q<EnumField>("ItemType").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemType = (ItemType)evt.newValue;
        });

        itemDetailsSection.Q<TextField>("Description").value = activeItem.itemDescription;
        itemDetailsSection.Q<TextField>("Description").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemDescription = evt.newValue;
        });

        itemDetailsSection.Q<IntegerField>("ItemUseRadius").value = activeItem.itemUseRadius;
        itemDetailsSection.Q<IntegerField>("ItemUseRadius").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemUseRadius = evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanPickedup").value = activeItem.canPickedup;
        itemDetailsSection.Q<Toggle>("CanPickedup").RegisterValueChangedCallback(evt =>
        {
            activeItem.canPickedup = evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanDropped").value = activeItem.canDropped;
        itemDetailsSection.Q<Toggle>("CanDropped").RegisterValueChangedCallback(evt =>
        {
            activeItem.canDropped = evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanCarried").value = activeItem.canCarried;
        itemDetailsSection.Q<Toggle>("CanCarried").RegisterValueChangedCallback(evt =>
        {
            activeItem.canCarried = evt.newValue;
        });

        itemDetailsSection.Q<IntegerField>("Price").value = activeItem.itemPrice;
        itemDetailsSection.Q<IntegerField>("Price").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemPrice = evt.newValue;
        });

        itemDetailsSection.Q<Slider>("SellPercentage").value = activeItem.sellPercentage;
        itemDetailsSection.Q<Slider>("SellPercentage").RegisterValueChangedCallback(evt =>
        {
            activeItem.sellPercentage = evt.newValue;
        });
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/751688.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

花卉寄售系统

摘 要 随着互联网的快速发展和普及&#xff0c;电子商务已经成为人们日常生活中不可或缺的一部分。在电子商务领域&#xff0c;花卉行业也逐渐崭露头角&#xff0c;成为一个具有巨大潜力的市场。传统的花卉销售模式通常是通过实体店面进行销售&#xff0c;这种模式存在着许多问…

Android开发系列(十二)Jetpack Compose之BottomSheet

BottomSheet 是 Android 中一个常用的 UI 组件&#xff0c;它通常用于显示从屏幕底部弹出的用户界面。Jetpack Compose 是 Android 中的一个全新 UI 工具包&#xff0c;它提供了一种声明式的方式来构建用户界面。Jetpack Compose 中也有一个名为 BottomSheet 的组件&#xff0c…

数据恢复篇:如何从 Mac 硬盘安全恢复丢失的文件

Mac RAID 阵列用于大存储。Mac RAID 上的数据丢失可能很复杂。一般来说&#xff0c;从 Mac RAID 硬盘恢复已删除的文件并不困难。但如果​​您想从 Mac RAID 硬盘恢复由于格式化、病毒感染、硬盘故障而丢失的文件&#xff0c;情况就会发生变化。您必须找到一个功能强大的 Mac R…

【ONLYOFFICE 8.1】的安装与使用——功能全面的 PDF 编辑器、幻灯片版式、优化电子表格的协作

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、ONLYOFFICE 简介三、安装1. Windows/Mac 安装2. 文档开发者版安装安装前准备使用 Docker 安装使用 Linux 发行版安装配置 ONLYOFFICE 文档开发者版集成和开发 四、使用1. 功能全面的 PDF 编辑器PDF 查看和导航P…

题解(A~D)

这次vp的比赛&#xff0c;我感觉前四道题虽然一点算法也没有&#xff0c;但是就是很难去做&#xff0c;要用数学思维去处理 第五题终究还是没有尝试&#xff0c;只能说才疏学浅吧&#xff0c;我只能说全是数学 话不多说&#xff0c;一起来看题目 A. X Axis 题意&#xff1a;…

【Redis】Java操作Redis(Jedis客户端使用)

Redis不仅支持简单的键值存储&#xff0c;还提供了丰富的数据结构&#xff08;如列表、哈希表、集合等&#xff09;和强大的原子操作&#xff0c;使得它在存储和处理数据时非常高效。关于这些数据结构的学习可以学习下面的博客&#xff1a; 【Redis】String的常用命令及图解St…

JS(JavaScript)DOM操作的趣味案例

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

业务境外系列(1)——玩转谷歌浏览器

最好用的浏览器之一&#xff0c;很多调试开发的标准版本。去官方下载安装&#xff0c;从其他渠道下载的&#xff0c;一般版本会落后一些&#xff0c;或者被内置了一些东西。下载地址:https://www.google.com/chrome/ 官网 &#xff0c;这样安装的时候比较正常。 查看版本: c…

spring-boot-starter-json配置对象属性为空不显示

问题背景 在Spring Boot中使用spring-boot-starter-json&#xff08;通常是通过jackson实现的&#xff09;时&#xff0c;如果你希望在序列化对象时&#xff0c;如果某个属性为空&#xff0c;则不显示该属性&#xff0c;你可以使用JsonInclude注解来实现这一点。 pom.xml <…

cs与msf权限传递以及mimikatz抓取win2012明文密码

启动服务端 进入客户端 建立监听 制作脚本 客户端运行程序 主机上线 打开msf 调用handler模块 创建监听 11.cs->msf 传递会话 12.传参完成 msf->cs会话传递 抓取密码&#xff08;null&#xff09; 修改注册表 shell reg add "HKEY_LOC…

1982Springboot宠物美容院管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot宠物美容院管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系 统具有完整的源代码和数据库…

[C#]基于opencvsharp实现15关键点人体姿态估计

数据集 正确选择数据集以对结果产生适当影响也是非常必要的。在此姿势检测中&#xff0c;模型在两个不同的数据集即COCO关键点数据集和MPII人类姿势数据集上进行了预训练。 1. COCO&#xff1a;COCO关键点数据集是一个多人2D姿势估计数据集&#xff0c;其中包含从Flickr收集的…

Redis集群(Clustering in Redis)工作机制详解

Redis集群工作机制详解 Redis 集群是用于提高 Redis 可扩展性和高可用性的解决方案。 维基百科&#xff1a;Scalability is the property of a system to handle a growing amount of work by adding resources to the system. 可扩展性是系统的一种允许通过增加系统资源来处…

Zookeeper:基于Zookeeper的分布式锁

一、Zookeeper分布式锁原理 二、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkClient。Curator。 Curator项目目标是简化Zookeeper客户端的使用。Curator最初是Netfix研发的&#xf…

Python | Leetcode Python题解之第202题快乐数

题目&#xff1a; 题解&#xff1a; def isHappy(self, n: int) -> bool:cycle_members {4, 16, 37, 58, 89, 145, 42, 20}def get_next(number):total_sum 0while number > 0:number, digit divmod(number, 10)total_sum digit ** 2return total_sumwhile n ! 1 an…

【UE5.3】笔记5-蓝图类

什么是蓝图类&#xff1a;其实就是C类&#xff0c;只不过是UE封装好的且可以直接拖出来可视化使用。 如何创建蓝图类&#xff1f;蓝图类有哪些&#xff1f; 蓝图类分为基于关卡的&#xff0c;基于Actor的&#xff0c;基于组件Component的。 基于关卡的蓝图类 一个关卡只能有…

Python | Leetcode Python题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; class Solution:def rangeBitwiseAnd(self, m: int, n: int) -> int:while m < n:# 抹去最右边的 1n n & (n - 1)return n

【Python实战因果推断】4_因果效应异质性4

目录 Cumulative Gain Target Transformation Cumulative Gain 如果采用与累积效应曲线完全相同的逻辑&#xff0c;但将每个点乘以累积样本 Ncum/N&#xff0c;就会得到累积增益曲线。现在&#xff0c;即使曲线的起点具有最高的效果&#xff08;对于一个好的模型来说&#x…

vue 实现 word/excel/ppt/pdf 等文件格式预览操作

效果图&#xff1a; 问题描述&#xff1a;一般情况下使用iframe标签就可以实现文件预览&#xff0c;但是这个标签只针对于ppt和pdf是有效的。对于doc文件就需要借助第三方插件&#xff08;vue-office/docx&#xff09;来实现预览了。下面介绍使用方法。 安装插件&#xff1a;n…

Golang | Leetcode Golang题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; func rangeBitwiseAnd(m int, n int) int {for m < n {n & (n - 1)}return n }