• 【Unity3D】UI Toolkit数据动态绑定


    1 前言

            本文将实现 cvs 表格数据与 UI Toolkit 元素的动态绑定。

            如果读者对 UI Toolkit 不是太了解,可以参考以下内容。

            本文完整资源见→UI Toolkit数据动态绑定

    2 数据动态绑定案例

    2.1 UI 搭建

            样式和 UI 层级结构如下。

            MainLayout.xml

    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    2. <Style src="project://database/Assets/Role/View/StyleSheets/RoleStyle.uss?fileID=7433441132597879392&guid=d93d80f270ec5014c90e97cc8c404d1f&type=3#RoleStyle" />
    3. <ui:VisualElement name="Background" style="flex-grow: 1; background-image: url('project://database/Assets/Role/Img/Background_Sky.png?fileID=2800000&guid=02ebb0e77ccd96143911134d6e39e1db&type=3#Background_Sky'); padding-left: 4%; padding-right: 4%; padding-top: 4%; padding-bottom: 4%; -unity-background-scale-mode: scale-and-crop;">
    4. <ui:Label text="Game Role" display-tooltip-when-elided="true" name="TitleLab" style="height: 10%; margin-bottom: 1%; -unity-text-align: middle-left; font-size: 100px; -unity-font-style: italic; color: rgb(34, 34, 34);" />
    5. <ui:VisualElement name="Body" style="flex-grow: 1; flex-direction: row;">
    6. <ui:VisualElement name="RoleTemplate" style="flex-basis: 25%; margin-left: 10px; margin-right: 10px; margin-top: 10px; margin-bottom: 10px; background-color: rgba(0, 0, 0, 0.2); border-top-left-radius: 10px; border-bottom-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px;">
    7. <ui:VisualElement name="Image" style="flex-basis: 50%; margin-left: 5%; margin-right: 5%; margin-top: 5%; margin-bottom: 0; background-color: rgba(0, 0, 0, 0.39); border-top-left-radius: 10px; border-top-right-radius: 10px; background-image: url('project://database/Assets/Role/Img/Avatar_1.png?fileID=2800000&guid=95b3aee3bc9bae64f8b70aba356b50b1&type=3#Avatar_1'); -unity-background-scale-mode: scale-and-crop;" />
    8. <ui:Label text="角色" display-tooltip-when-elided="true" name="NameLab" style="margin-left: 3%; margin-right: 3%; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; background-color: rgb(255, 96, 96); border-top-left-radius: 10px; border-bottom-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; flex-shrink: 1; font-size: 35px; -unity-text-align: middle-center; color: rgb(255, 254, 254);" />
    9. <ui:VisualElement name="Properties" style="flex-grow: 1; margin-left: 5%; margin-right: 5%; margin-top: 0; margin-bottom: 5%; background-color: rgba(0, 0, 0, 0.39); border-bottom-right-radius: 10px; border-bottom-left-radius: 10px;">
    10. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    11. <ui:Label text="等级" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    12. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    13. ui:VisualElement>
    14. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    15. <ui:Label text="行动力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    16. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    17. ui:VisualElement>
    18. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    19. <ui:Label text="最大HP" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    20. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    21. ui:VisualElement>
    22. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    23. <ui:Label text="最大MP" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    24. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    25. ui:VisualElement>
    26. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    27. <ui:Label text="攻击力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    28. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    29. ui:VisualElement>
    30. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    31. <ui:Label text="防御力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    32. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    33. ui:VisualElement>
    34. ui:VisualElement>
    35. ui:VisualElement>
    36. ui:VisualElement>
    37. ui:VisualElement>
    38. ui:UXML>

            RoleStyle.uss

    1. #RoleTemplate:hover {
    2. transition-duration: 0.1s;
    3. translate: 0 -20px;
    4. border-left-width: 5px;
    5. border-right-width: 5px;
    6. border-top-width: 5px;
    7. border-bottom-width: 5px;
    8. border-left-color: rgb(248, 242, 242);
    9. border-right-color: rgb(248, 242, 242);
    10. border-top-color: rgb(248, 242, 242);
    11. border-bottom-color: rgb(248, 242, 242);
    12. }
    13. #Property Label {
    14. font-size: 25px;
    15. color: rgba(0, 0, 0, 255);
    16. -unity-text-align: middle-center;
    17. -unity-font-style: bold;
    18. }

            显示效果如下。

    2.2 创建模板

            在 Hierarchy 窗口选中 RoleTemplate 元素,右键弹出菜单,选择 Create Template,选择 Resources 目录下保存 RoleTemplate.uxml,修改 Grow 为 1。

            RoleTemplate.xml

    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    2. <ui:VisualElement name="RoleTemplate" style="flex-basis: 25%; margin-left: 10px; margin-right: 10px; margin-top: 10px; margin-bottom: 10px; background-color: rgba(0, 0, 0, 0.2); border-top-left-radius: 10px; border-bottom-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; flex-grow: 1;">
    3. <ui:VisualElement name="Image" style="flex-basis: 50%; margin-left: 5%; margin-right: 5%; margin-top: 5%; margin-bottom: 0; background-color: rgba(0, 0, 0, 0.39); border-top-left-radius: 10px; border-top-right-radius: 10px; background-image: url('project://database/Assets/Role/Img/Avatar_1.png?fileID=2800000&guid=95b3aee3bc9bae64f8b70aba356b50b1&type=3#Avatar_1'); -unity-background-scale-mode: scale-and-crop;" />
    4. <ui:Label text="角色" display-tooltip-when-elided="true" name="NameLab" style="margin-left: 3%; margin-right: 3%; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; background-color: rgb(255, 96, 96); border-top-left-radius: 10px; border-bottom-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; flex-shrink: 1; font-size: 35px; -unity-text-align: middle-center; color: rgb(255, 254, 254);" />
    5. <ui:VisualElement name="Properties" style="flex-grow: 1; margin-left: 5%; margin-right: 5%; margin-top: 0; margin-bottom: 5%; background-color: rgba(0, 0, 0, 0.39); border-bottom-right-radius: 10px; border-bottom-left-radius: 10px;">
    6. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    7. <ui:Label text="等级" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    8. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    9. ui:VisualElement>
    10. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    11. <ui:Label text="行动力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    12. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    13. ui:VisualElement>
    14. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    15. <ui:Label text="最大HP" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    16. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    17. ui:VisualElement>
    18. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    19. <ui:Label text="最大MP" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    20. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    21. ui:VisualElement>
    22. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    23. <ui:Label text="攻击力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    24. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    25. ui:VisualElement>
    26. <ui:VisualElement name="Property" style="flex-direction: row; margin-left: 5px; margin-right: 5px; margin-top: 5px; margin-bottom: 5px; flex-grow: 0; justify-content: center;">
    27. <ui:Label text="防御力" display-tooltip-when-elided="true" name="Name" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(185, 251, 192); border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    28. <ui:Label text="1" display-tooltip-when-elided="true" name="Value" style="flex-basis: 50%; flex-shrink: 1; background-color: rgb(255, 200, 200); border-top-right-radius: 10px; border-bottom-right-radius: 10px; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0;" />
    29. ui:VisualElement>
    30. ui:VisualElement>
    31. ui:VisualElement>
    32. ui:UXML>

            保存模板后,删除 Hierarchy 窗口中的 RoleTemplate 元素,后面会通过脚本加载 RoleTemplate。

    2.3 自定义元素

            RoleView.cs

    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. public class RoleView : VisualElement {
    5. // 便于在UI Builder中导入自定义UI, 需要有无参构造函数
    6. public new class UxmlFactory : UxmlFactory<RoleView> {}
    7. private TemplateContainer container; // 模板容器
    8. private List properties; // 角色属性
    9. public RoleView() {
    10. container = Resources.Load("RoleTemplate").Instantiate();
    11. container.style.flexGrow = 1;
    12. hierarchy.Add(container);
    13. properties = container.Query("Property").ToList();
    14. }
    15. public RoleView(RoleData roleData) : this() {
    16. userData = roleData;
    17. UpdateRoleData();
    18. container.RegisterCallback(OnClick);
    19. }
    20. private void OnClick(MouseDownEvent mouseDownEvent) { // 单击角色模板回调函数
    21. RoleData roleData = (RoleData) userData;
    22. if (mouseDownEvent.button == 0) { // 按下鼠标左键
    23. roleData.RoleLevel++;
    24. } else if (mouseDownEvent.button == 1) { // 按下鼠标右键
    25. roleData.RoleLevel--;
    26. }
    27. UpdateRoleData();
    28. }
    29. private void UpdateRoleData() { // 更新角色数据
    30. RoleData roleData = (RoleData) userData;
    31. container.Q("Image").style.backgroundImage = roleData.RoleImage;
    32. container.Q
    33. SetProperty(properties[0], roleData.RoleLevel);
    34. SetProperty(properties[1], roleData.LevelData.initiative);
    35. SetProperty(properties[2], roleData.LevelData.maxHp);
    36. SetProperty(properties[3], roleData.LevelData.maxMp);
    37. SetProperty(properties[4], roleData.LevelData.attack);
    38. SetProperty(properties[5], roleData.LevelData.defense);
    39. }
    40. private void SetProperty(VisualElement property, int value) { // 更新角色属性
    41. property.Q
    42. }
    43. }

    2.4 自定义数据

            LevelData.cs

    1. public class LevelData { // 等级属性数据
    2. public int initiative; // 主动权(行动力/速度)
    3. public int maxHp; // 最大生命值
    4. public int maxMp; // 最大魔法值
    5. public int attack; // 攻击力
    6. public int defense; // 防御力
    7. }

            RoleData.cs

    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. [CreateAssetMenu(menuName = ("RoleData"), fileName = ("RoleData_"))]
    4. public class RoleData : ScriptableObject { // 角色属性数据
    5. private const int roleMaxLevel = 10; // 最大等级
    6. [SerializeField]
    7. private TextAsset levelDataFile; // 等级数据csv文件
    8. [SerializeField]
    9. private Texture2D roleImage; // 角色头像
    10. [SerializeField]
    11. private string roleName; // 角色名
    12. [SerializeField, Range(1, roleMaxLevel)]
    13. private int roleStartLevel = 1; // 角色开始等级
    14. [SerializeField]
    15. private List levelDatas; // 等级数据
    16. private int roleLevel; // 角色当前等级
    17. public Texture2D RoleImage => roleImage; // 获取角色头像
    18. public string RoleName => roleName; // 获取角色名
    19. public int RoleLevel { // 获取/设置角色等级
    20. get => roleLevel;
    21. set {
    22. if (roleLevel == value || value < 1 || value > roleMaxLevel) {
    23. return;
    24. }
    25. roleLevel = value;
    26. }
    27. }
    28. public LevelData LevelData => levelDatas[roleLevel - 1]; // 获取角色等级数据
    29. private void OnEnable() {
    30. roleLevel = roleStartLevel;
    31. }
    32. private void OnValidate() {
    33. if (levelDataFile == null) {
    34. return;
    35. }
    36. if (levelDatas == null) {
    37. levelDatas = new List();
    38. }
    39. levelDatas.Clear();
    40. string[] textInLines = levelDataFile.text.Split('\n');
    41. for (int i = 1; i < textInLines.Length; i++) {
    42. string[] statsValues = textInLines[i].Split(",");
    43. LevelData levelData = new LevelData();
    44. levelData.initiative = int.Parse(statsValues[0]);
    45. levelData.maxHp = int.Parse(statsValues[1]);
    46. levelData.maxMp = int.Parse(statsValues[2]);
    47. levelData.attack = int.Parse(statsValues[3]);
    48. levelData.defense = int.Parse(statsValues[4]);
    49. levelDatas.Add(levelData);
    50. }
    51. }
    52. }

            编译后,在 Assets 窗口右键,依次选择【Create→RoleData】,创建 4 个对象,对应 4 个角色的配置,分别重命名为 RoleData_1.asset、RoleData_2.asset、RoleData_3.asset、RoleData_4.asset。

            选中 ScriptableObject 配置文件后,在 Inspector 窗口配置角色属性。

            其中 LevelDataFile 是角色每个等级的属性 cvs 表,内容如下。

    2.5 元素加载

            RoleLoader.cs

    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. public class RoleLoader : MonoBehaviour {
    5. [SerializeField]
    6. private List roleDatas; // 角色数据
    7. private VisualElement root; // 根容器
    8. private void Awake() {
    9. root = GetComponent().rootVisualElement;
    10. var bodyContainer = root.Q("Body");
    11. bodyContainer.Clear();
    12. for(int i = 0; i < roleDatas.Count; i++) {
    13. RoleView roleView = new RoleView(roleDatas[i]);
    14. roleView.style.flexBasis = Length.Percent(25.0f);
    15. bodyContainer.Add(roleView);
    16. }
    17. }
    18. }

            说明:RoleLoader 脚本组件挂在 UIDocument 对象上,并且需要将 RoleData_1.asset、RoleData_2.asset、RoleData_3.asset、RoleData_4.asset 赋给 RoleDatas,如下。

    2.6 运行效果

            运行效果如下,单击卡片,角色的等级会升 1 级,等级属性也会按照 cvs 表格中的策略数据同步更新。

  • 相关阅读:
    开机自启动Linux and windows
    一起来学Kotlin:概念:16. Kotlin Scope Function 作用域函数:let,run,with,apply,also
    非目标代谢组学(untargeted metabolomics)中常用的方法学考察的方法(四)
    SAP SD定价过程 含税&未税 最大区别
    软件架构设计(九) 架构评估(复审)
    将数字每千分位用逗号隔开
    我们追求的泛化,竟是一条死路?
    通配符ssl证书的作用有哪些?为什么通配符ssl证书如此受欢迎?
    win下 lvgl模拟器codeblocks配置
    猿创征文|Java实现自定义注解
  • 原文地址:https://blog.csdn.net/m0_37602827/article/details/132815013