• 【Unity3D】UI Toolkit样式选择器


    1 前言

            UI Toolkit简介 中介绍了样式属性UI Toolkit容器 和 UI Toolkit元素 中介绍了容器和元素,本文将介绍样式选择器(Selector),主要包含样式类选择器(Class Selector)、C# 类选择器(Type Selector)、名称选择器(Name Selector)、通用选择器(Universal Selector)、后代选择器(Descendant Selector)、子选择器(Child Selector)、多重选择器(Multiple Selector)、伪类选择器(Pseudo Class)等。样式选择器官方介绍见→USS selectors

    2 简单选择器(Simple Selector) 

            简单选择器优先级:

    1. // * < C# Type < .Name < #Name
    2. // 通用选择器 < C#类选择器 < 样式类选择器 < 名称选择器
    3. Universal Selector < Type Selector < Class Selector < Name Selector

    2.1 样式类选择器(Class Selector)

            Class 选择器是命名以 "." 号开头的选择器(如:.red、.abc、.xyz 等),需要手动绑定到元素上,官方介绍见→Class selectors

            1)创建 UI

            在 UI Builder 的 Hierarchy 窗口中创建 UI 如下。

            显示如下。 

            2)创建 USS 文件

            在 StyleSheets 窗口点击 "+" 号,选择 Create New USS 选项,如下。选择 USS 文件保存路径,命名为 StyleSelectorDemo。

            3)创建选择器

            在 StyleSheets 窗口的 selector 框中输入 ".textColor",如下。注意:textColor 前面有个点,命名可以随意,如:demo、test 等都行。

            按 Enter 键后,创建了 selector,如下。

            4)修改选择器的属性

            选中 ".textColor" 选择器,在 Inspector 窗口修改文本颜色,如下。

            5)绑定选择器到元素

            将 ".textColor" 选择器拖拽到 Hierarchy 或 Viewport 窗口中相关元素上,实现样式选择器与元素的绑定。

            也可以通过以下方式绑定元素:选中元素后,在 Inspector 窗口的 Style Class List 中添加 selector,如下。 

            选择器绑定到元素后,在 Inspector 窗口可以看到元素绑定的选择器,如下。可以通过后面的 "x" 号删除选择器。

            6)显示效果

            Label 和 Button 都手动绑定了 ".textColor" 选择器,显示效果如下。 

    2.2 C# 类选择器(Type Selector)

            Type 选择器是以元素的 C# 类名命名的选择器(如:Label、Button、VisualElement 等),会自动绑定到对应 Type 的元素上,不需要手动绑定,官方介绍见→Type selectors

            1)创建选择器

            在 StyleSheets 窗口创建名为 "Label" 的选择器,如下。

            2)修改选择器的属性

            选中 "Label" 选择器,在 Inspector 窗口修改文本样式为斜体,如下。

            3)显示效果

            Label 元素会自动绑定 "Label" 选择器,Button 元素则不会,即使手动将 "Label" 选择器拖拽到 Button 元素上,也不会绑定成功。显示效果如下。

    2.3 名称选择器(Name Selector)

            Name 选择器是命名以 "#" 号开头的选择器(如:#Name、#Abc、#Xyz 等),会自动绑定到对应 Name 的元素上,不需要手动绑定,官方介绍见→Name selectors

            1)修改元素名

            新创建的元素默认元素名为空,修改元素名如下。

            2)创建选择器

            在 StyleSheets 窗口创建名为 "Button1" 的选择器,如下。

            3)修改选择器的属性 

            选中 "Button1" 选择器,在 Inspector 窗口修改背景颜色,如下。 

            4)显示效果

            Button1 元素会自动绑定 "Button1" 选择器,Label1 元素则不会,即使手动将 "Button1" 选择器拖拽到 Label1 元素上,也不会绑定成功。显示效果如下。

    2.4 通用选择器(Universal Selector)

            Universal 选择器是以 "*" 号命名的选择器,会自动绑定到所有元素上,不需要手动绑定,官方介绍见→Universal selectors

            1)创建选择器

            在 StyleSheets 窗口创建名为 "*" 的选择器,如下。

            2)修改选择器的属性 

            选中 "*" 选择器,在 Inspector 窗口修改边框宽度和颜色,如下。 

            3)显示效果

            所有元素都会自动绑定 "*" 选择器,显示效果如下。

    3 复杂选择器(Complex Selector) 

            复杂选择器是指由多个简单选择器按照特定规则组合而成的选择器。

    3.1 后代选择器(Descendant Selector)

            Descendant 选择器由多个简单选择器通过空格连接而成,它匹配的是某个 UI 元素底下符合规则的所有层级的子元素,官方介绍见→Descendant selectors

    1. // 在selector1匹配的子元素中匹配selector2, ...
    2. // 选择器的顺序不同匹配的元素也不同
    3. selector1 selector2 {...}

            1)UI 搭建

            UI 层级结构如下,其中 Background、VE1、VE2、VE3 都是 VisualElement,Label1、Label2、Label3 都是 Label。

            创建以下简单选择器。其中,Lable 选择器中修改了字体大小为 30;.red 选择器中修改了背景颜色为红色,并绑定到 VE1,.green 选择器中修改了背景颜色为绿色,并绑定到 VE2;.blue 选择器中修改了背景颜色为蓝色,并绑定到 VE3。

            UI 显示如下。

            2)创建 Descendant 选择器

            在 StyleSheets 窗口创建以下选择器。

    • "#VE1 Label" 选择器:修改字体为斜体;
    • ".green Label" 选择器:修改字体颜色为黑色;
    • "#Background *" 选择器:设置 3px 的黄色边框。

            3)显示效果

            可以看到,"#VE1 Label" 选择器匹配的是 Label1 元素,".green Label" 选择器匹配的是 Label2 元素,"#Background *" 选择器匹配的是 VE1、VE2、VE3、Label1、Label2、Label3 元素。

    3.2 子选择器(Child Selector)

            Child 选择器由多个简单选择器通过 " > " 连接而成,它匹配的是某个 UI 元素底下符合规则的第一层级的子元素,官方介绍见→Child selectors

    1. // 在selector1匹配的子元素中匹配selector2, ...
    2. // 选择器的顺序不同匹配的元素也不同
    3. selector1 > selector2 {...}

            1)UI 搭建

            同 3.1 1)节。

            2)创建 Child 选择器

            在 StyleSheets 窗口创建以下选择器。

    • "#VE1 > Label" 选择器:修改字体为斜体;
    • ".green > Label" 选择器:修改字体颜色为黑色;
    • "#Background > *" 选择器:设置 3px 的黄色边框。

            3)显示效果

            可以看到,"#VE1 > Label" 选择器匹配的是 Label1 元素,".green > Label" 选择器匹配的是 Label2 元素,"#Background > *" 选择器匹配的是 VE1、VE2、VE3 元素。

    3.3 多重选择器(Multiple Selector)

            Multiple 选择器由多个简单选择器直接而成,它匹配的是符合所有规则的元素,官方介绍见→Multiple selectors

    1. // 匹配同时满足selector1、selector2、...的元素
    2. // 选择器的顺序不同匹配的元素相同
    3. selector1selector2 {...}

            说明:Class 选择器可以通过 "." 区分,Name 选择器可以通过 "#" 区分,Type 选择器没有区分符号,因此,一个多重选择器中最多允许有一个 Type 选择器,并且必须放在第一位。 

            1)UI 搭建

            同 3.1 1)节。

            2)创建 Multiple 选择器

            在 StyleSheets 窗口创建以下选择器。

    • "Label#Label1" 选择器:修改字体为斜体;
    • "VisualElement.green" 选择器:设置圆角半径 Radius 为 20 px;
    • "Label*" 选择器:设置 3px 的黄色边框。

            3)显示效果

            可以看到,"Label#Label1" 选择器匹配的是 Label1 元素,"VisualElement.green" 选择器匹配的是 VE2 元素,"Label*" 选择器匹配的是 Label1、Label1、Label3 元素。

    4 伪类选择器(Pseudo Class)

            Pseudo 选择器是指由简单选择器和状态符连接而成,它匹配的是特定状态下的元素,官方介绍见→Pseudo-classes

    1. // 匹配满足selector且进入state状态的元素
    2. selector:state {...}

            状态符主要以下几种。

    • :hover:光标悬浮在元素上。
    • :active:用户与元素交互。
    • :inactive:用户停止与元素交互。
    • :focus:元素获得焦点。
    • :disabled:元素进入 disabled 状态。
    • :enabled:元素进入 enabled 状态。
    • :checked:Toggle 或 RadioButton 被选中。
    • :root:元素成为根元素。

            1)UI 搭建

            同 3.1 1)节。

            2)创建 Pseudo 选择器

            在 StyleSheets 窗口创建以下选择器。

    • "#Label1:hover" 选择器:修改字体为斜体;
    • ".green:hover" 选择器:设置圆角半径 Radius 为 20 px;
    • "*:hover" 选择器:设置 3px 的黄色边框。

            3)显示效果

             可以看到,"#Label1:hover" 选择器匹配的是进入 hover 状态的 Label1 元素,".green:hover" 选择器匹配的是进入 hover 状态的 VE2 元素,"*:hover" 选择器匹配的是进入 hover 状态的 VE1、VE2、VE3、Label1、Label1、Label3 元素。

    5 样式切换

            1)样式选择器的添加和删除

    1. // 如果visualElement有StyleName样式, 就将其删除; 如果visualElement没有StyleName样式, 就将其添加
    2. visualElement.ToggleInClassList("StyleName"); // StyleName是样式选择器名, 不需要前面的"."

            说明:只能添加和删除样式类选择器(以 "." 命名开头的选择器),其他选择器都是自动绑定到元素上的。  

            2)uss 样式文件替换

    1. VisualElement root = GetComponent().rootVisualElement; // 根容器
    2. VisualElementStyleSheetSet styleSheetSet = root.styleSheets; // 样式集合
    3. styleSheetSet.Remove(oldStyleSheet); // 移除旧样式, oldStyleSheet是StyleSheet类型变量, 指向一个uss文件
    4. styleSheetSet.Add(newlightTheme); // 添加新样式, newStyleSheet是StyleSheet类型变量, 指向一个uss文件

    6 样式应用

            本节将实现亮主题和暗主题的切换,完整资源见→Unity3D切换样式主题。 

            Page.uxml

    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/SwitchTheme/StyleSheets/LightTheme.uss?fileID=7433441132597879392&guid=b86be23b06b471b43a7ea453aed7df74&type=3#LightTheme" />
    3. <ui:VisualElement name="Background" class="bgColor" style="flex-direction: row; flex-grow: 1; background-image: url('project://database/Assets/SwitchTheme/Textures/Background_Sky.png?fileID=2800000&guid=49e1c76bfa6ef0546a39fd2bceb69b9a&type=3#Background_Sky');">
    4. <ui:VisualElement name="Left" style="flex-grow: 0; border-right-width: 2px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); flex-basis: 30%;">
    5. <ui:VisualElement name="Top" class="dark top" style="flex-basis: 30%; margin-bottom: 0; border-bottom-width: 2px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0);" />
    6. <ui:VisualElement name="Middle" style="flex-basis: auto; flex-grow: 1;">
    7. <ui:Label text="Label" display-tooltip-when-elided="true" class="item middleBg middle" style="flex-grow: 1; -unity-text-align: middle-center; font-size: 60px; flex-shrink: 1; margin-top: 5px; margin-bottom: 5px;" />
    8. <ui:Label text="Theme" display-tooltip-when-elided="true" name="Theme" class="item middle" style="flex-grow: 1; -unity-text-align: middle-center; font-size: 60px; flex-shrink: 1; margin-top: 5px; margin-bottom: 5px;" />
    9. <ui:RadioButtonGroup value="-1" choices="Light,Drak" name="SwitchTheme" class="middle hide" style="flex-grow: 0; font-size: 45px; -unity-text-align: middle-center; align-items: center; justify-content: center; flex-direction: column; margin-left: 0; margin-right: 0; margin-top: 5px; margin-bottom: 5px; flex-shrink: 1;" />
    10. <ui:Label text="Label" display-tooltip-when-elided="true" class="item middle" style="flex-grow: 1; -unity-text-align: middle-center; font-size: 60px; flex-shrink: 1; margin-top: 5px; margin-bottom: 5px;" />
    11. ui:VisualElement>
    12. <ui:VisualElement name="Bottom" style="flex-basis: 25%; border-top-width: 2px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0);">
    13. <ui:Label text="Bottom" display-tooltip-when-elided="true" style="flex-shrink: 1; flex-grow: 1; font-size: 100px; -unity-text-align: middle-center;" />
    14. ui:VisualElement>
    15. ui:VisualElement>
    16. <ui:VisualElement name="Right" style="flex-grow: 0; flex-basis: 70%; align-items: center; justify-content: center;">
    17. <ui:Label text="Work Space" display-tooltip-when-elided="true" class="right" />
    18. ui:VisualElement>
    19. ui:VisualElement>
    20. ui:UXML>

            LightTheme.uss

    1. Label {
    2. color: rgb(48, 47, 47);
    3. }
    4. RadioButton:hover {
    5. background-color: rgb(217, 217, 217);
    6. }
    7. .unity-radio-button__checkmark-background {
    8. margin-right: 10px;
    9. width: 30px;
    10. height: 30px;
    11. justify-content: center;
    12. align-items: center;
    13. border-left-width: 1px;
    14. border-right-width: 1px;
    15. border-top-width: 1px;
    16. border-bottom-width: 1px;
    17. border-top-left-radius: 20px;
    18. border-bottom-left-radius: 20px;
    19. border-top-right-radius: 20px;
    20. border-bottom-right-radius: 20px;
    21. background-color: rgb(43, 43, 43);
    22. border-left-color: rgba(248, 242, 242, 255);
    23. border-right-color: rgba(248, 242, 242, 255);
    24. border-top-color: rgba(248, 242, 242, 255);
    25. border-bottom-color: rgba(248, 242, 242, 255);
    26. padding-top: 0;
    27. }
    28. .unity-radio-button__checkmark {
    29. width: 15px;
    30. height: 15px;
    31. border-top-left-radius: 10px;
    32. border-bottom-left-radius: 10px;
    33. border-top-right-radius: 10px;
    34. border-bottom-right-radius: 10px;
    35. justify-content: center;
    36. align-items: center;
    37. background-color: rgb(217, 213, 213);
    38. }
    39. .bgColor {
    40. -unity-background-image-tint-color: rgb(255, 255, 255);
    41. }
    42. .top {
    43. background-image: url('project://database/Assets/SwitchTheme/Textures/unity_dark.png?fileID=2800000&guid=49ee81a1e2e15df46968d5d1978abc12&type=3#unity_dark');
    44. -unity-background-scale-mode: scale-to-fit;
    45. }
    46. .middle {
    47. background-color: rgba(0, 239, 255, 0.39);
    48. }
    49. .right {
    50. -unity-text-align: middle-center;
    51. -unity-font-style: bold;
    52. font-size: 200px;
    53. color: rgb(0, 168, 255);
    54. justify-content: center;
    55. align-items: center;
    56. -unity-text-outline-width: 1px;
    57. -unity-text-outline-color: rgb(255, 31, 0);
    58. text-shadow: 5px 2px 1px rgb(255, 255, 255);
    59. }
    60. .hide {
    61. display: none;
    62. }
    63. .item:hover {
    64. background-color: rgb(58, 56, 56);
    65. color: rgb(219, 216, 216);
    66. }
    67. .middle {
    68. background-color: rgba(0, 239, 255, 0.39);
    69. }

            DarkTheme.uss

    1. Label {
    2. color: rgb(212, 212, 212);
    3. }
    4. RadioButton:hover {
    5. background-color: rgb(38, 38, 38);
    6. }
    7. .unity-radio-button__checkmark-background {
    8. margin-right: 10px;
    9. width: 30px;
    10. height: 30px;
    11. justify-content: center;
    12. align-items: center;
    13. border-left-width: 1px;
    14. border-right-width: 1px;
    15. border-top-width: 1px;
    16. border-bottom-width: 1px;
    17. border-top-left-radius: 20px;
    18. border-bottom-left-radius: 20px;
    19. border-top-right-radius: 20px;
    20. border-bottom-right-radius: 20px;
    21. background-color: rgb(255, 255, 255);
    22. padding-top: 0;
    23. }
    24. .unity-radio-button__checkmark {
    25. width: 15px;
    26. height: 15px;
    27. border-top-left-radius: 10px;
    28. border-bottom-left-radius: 10px;
    29. border-top-right-radius: 10px;
    30. border-bottom-right-radius: 10px;
    31. justify-content: center;
    32. align-items: center;
    33. background-color: rgb(51, 50, 50);
    34. }
    35. .bgColor {
    36. -unity-background-image-tint-color: rgb(132, 132, 132);
    37. }
    38. .top {
    39. background-image: url('project://database/Assets/SwitchTheme/Textures/unity_light.png?fileID=2800000&guid=92a215376eed0c9498000506d15b4afe&type=3#unity_light');
    40. -unity-background-scale-mode: scale-to-fit;
    41. }
    42. .middle {
    43. background-color: rgba(46, 44, 44, 0.39);
    44. }
    45. .right {
    46. -unity-text-align: middle-center;
    47. -unity-font-style: bold;
    48. font-size: 200px;
    49. color: rgb(197, 194, 194);
    50. justify-content: center;
    51. align-items: center;
    52. -unity-text-outline-width: 1px;
    53. -unity-text-outline-color: rgb(255, 216, 0);
    54. text-shadow: 5px 2px 1px rgb(53, 52, 52);
    55. }
    56. .hide {
    57. display: none;
    58. }
    59. .item:hover {
    60. background-color: rgb(214, 211, 211);
    61. color: rgb(46, 45, 45);
    62. }

            SwitchTheme.cs

    1. using UnityEngine;
    2. using UnityEngine.UIElements;
    3. public class SwitchTheme : MonoBehaviour {
    4. private VisualElement root; // 根容器
    5. private RadioButtonGroup switchThemeElement; // 切换主题元素
    6. private VisualElementStyleSheetSet styleSheetSet; // 主题集合
    7. [SerializeField] private StyleSheet lightTheme; // 亮主题, 指向LightTheme.uss文件
    8. [SerializeField] private StyleSheet darkTheme; // 暗主题, 指向DarkTheme.uss文件
    9. private void Awake() {
    10. root = GetComponent().rootVisualElement;
    11. styleSheetSet = root.styleSheets;
    12. Label themeLabel = root.Q
    13. themeLabel.RegisterCallback(OnClick);
    14. switchThemeElement = root.Q("SwitchTheme");
    15. switchThemeElement.RegisterValueChangedCallback(OnValueChanged);
    16. }
    17. private void OnClick(ClickEvent e) { // 点击回调函数
    18. switchThemeElement.ToggleInClassList("hide");
    19. }
    20. private void OnValueChanged(ChangeEvent<int> e) { // value变化回调函数
    21. if (e.newValue == 0) { // 切换为亮主题
    22. styleSheetSet.Remove(darkTheme);
    23. styleSheetSet.Add(lightTheme);
    24. } else { // 切换为暗主题
    25. styleSheetSet.Remove(lightTheme);
    26. styleSheetSet.Add(darkTheme);
    27. }
    28. }
    29. }

            运行效果如下。

  • 相关阅读:
    DLL注入——使用全局钩子
    【SRE】MySQL8使用方式
    Linux常用命令——clock命令
    【毕业设计】RFID智能门禁系统 - 单片机 物联网 嵌入式
    Python 算法高级篇:贪心算法的原理与应用
    盘点ERP开发的那点事-业务流和数据流
    uni-app:获取当前经纬度解决方案+如何布置全局组件
    vue3项目服务器静态文件部署增加指定路由地址完整实现
    构建工具 Vite、Webpack、Rollup对比
    在嵌入式设计中添加双向I2C数字隔离
  • 原文地址:https://blog.csdn.net/m0_37602827/article/details/132670657