【Attribute】Inspector视图枚举字段范围限定特性

简介

        为了提升枚举的复用性,有时候我们可以通过限定枚举字段的范围来避免定义新的枚举类型,例如有一个代表方向的枚举(包括None,Left,Up,Right,Down),全局方向(Left,Up,Right,Down),水平方向(Left,Right),竖直方向(Up,Down)。

代码示例(C#)

EnumRangeAttribute.cs

using System;
using System.Linq;
using UnityEngine;/// <summary>
/// 枚举范围限定特性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class EnumRangeAttribute : PropertyAttribute
{/// <summary>/// 枚举最小值/// </summary>public int mMin { get; }/// <summary>/// 枚举最大值/// </summary>public int mMax { get; }/// <summary>/// 枚举名称合集/// </summary>public string[] mEnumNames { get => enumNames?.ToArray(); }/// <summary>/// 枚举值合集/// </summary>public int[] mEnumValues { get => enumValues?.ToArray(); }/// <summary>/// 枚举范围特性模式/// </summary>public EnumRangeMode mEnumRangeMode { get; }private string[] enumNames;private int[] enumValues;/// <summary>/// 构造函数/// </summary>/// <param name="min">枚举最小值</param>/// <param name="max">枚举最大值</param>public EnumRangeAttribute(int min, int max){mMin = min;mMax = max;mEnumRangeMode = EnumRangeMode.MinAndMax;}/// <summary>/// 构造函数/// </summary>/// <param name="enumNames">枚举名称合集 (大小写敏感)</param>public EnumRangeAttribute(params string[] enumNames){this.enumNames = enumNames;mEnumRangeMode = EnumRangeMode.EnumNames;}/// <summary>/// 构造函数/// </summary>/// <param name="enumValues">枚举值合集</param>public EnumRangeAttribute(int[] enumValues){this.enumValues = enumValues;mEnumRangeMode = EnumRangeMode.EnumValues;}/// <summary>/// 枚举范围特性模式/// </summary>public enum EnumRangeMode{MinAndMax, EnumNames, EnumValues}
}

EnumRangeAttributeDrawer.cs

using UnityEngine;
using UnityEditor;
using System;
using System.Linq;/// <summary>
/// 枚举范围限定特性绘制器
/// </summary>
[CustomPropertyDrawer(typeof(EnumRangeAttribute))]
public class EnumRangeAttributeDrawer : PropertyDrawer
{private EnumRangeAttribute enumRangeAttribute; // 枚举范围特性private Type enumType; // 枚举类型private string[] rawEnumNames; // 枚举名称原始合集private string[] displayNames; // 下拉菜单显示名称合集private int selectedIndex; // 当前所选中的选项索引private int preIndex; // 所选中的选项索引的副本private bool isLockGUI; // 是否锁定GUI的绘制private bool isInit; // 是否初始化private string warningText; // 警告信息private string preWarningText; // 警告信息副本public override float GetPropertyHeight(SerializedProperty property, GUIContent label){return EditorGUI.GetPropertyHeight(property, label, true);}public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){if (fieldInfo.FieldType.IsEnum){Init(property);if (!isLockGUI){selectedIndex = EditorGUI.Popup(position, label, selectedIndex, displayNames.Select(n => new GUIContent(n)).ToArray());if (selectedIndex != preIndex){preIndex = selectedIndex;property.enumValueIndex = IndexOf(displayNames[selectedIndex]);}}}else warningText = $"Warning:The type of the field '{fieldInfo.Name}' marked with 'EnumRange' attribute is not 'Enum'.";if (!warningText.Equals(preWarningText)){Debug.LogWarning(warningText);preWarningText = warningText;}}// 初始化private void Init(SerializedProperty property){if (!isInit){isLockGUI = true;isInit = true;enumRangeAttribute = (EnumRangeAttribute)attribute;if (enumRangeAttribute == null){warningText = $"Warning:The field '{fieldInfo.Name}' is not marked 'EnumRange' attribute.";return;}enumType = fieldInfo.FieldType;rawEnumNames = property.enumNames;if (rawEnumNames == null || rawEnumNames.Length == 0){warningText = $"Warning:The enum's names of the field '{property.name}' is null or empty.";return;}if (!InitDisplayNames()) displayNames = rawEnumNames;selectedIndex = Array.FindIndex(displayNames, n => n.Equals(rawEnumNames[property.enumValueIndex]));if (selectedIndex == -1) selectedIndex = 0;preIndex = selectedIndex;warningText = string.Empty;preWarningText = string.Empty;isLockGUI = false;}}// 初始化枚举下拉菜单显示名称合集private bool InitDisplayNames(){switch (enumRangeAttribute.mEnumRangeMode){case EnumRangeAttribute.EnumRangeMode.MinAndMax:return MinAndMaxInit();case EnumRangeAttribute.EnumRangeMode.EnumNames:return EnumNamesInit();case EnumRangeAttribute.EnumRangeMode.EnumValues:return EnumValuesInit();}return false;}// MinAndMax模式初始化private bool MinAndMaxInit(){if (enumRangeAttribute.mMin > enumRangeAttribute.mMax) return false;var v_values = Enum.GetValues(enumType).Cast<int>();if (v_values.Count() == 0) return false;v_values = v_values.Where(val => val >= enumRangeAttribute.mMin && val <= enumRangeAttribute.mMax);if (v_values.Count() == 0) return false;var v_names = v_values.Select(val => Enum.GetName(enumType, val));if (v_names.Count() == 0) return false;displayNames = v_names.ToArray();return true;}// EnumNames模式初始化private bool EnumNamesInit(){if (enumRangeAttribute.mEnumNames == null || enumRangeAttribute.mEnumNames.Length == 0) return false;var v_names = enumRangeAttribute.mEnumNames.Where(n => Array.FindIndex(rawEnumNames, en => en.Equals(n)) != -1);if (v_names.Count() == 0) return false;displayNames = v_names.ToArray();return true;}// EnumValues模式初始化private bool EnumValuesInit(){if (enumRangeAttribute.mEnumValues == null || enumRangeAttribute.mEnumValues.Length == 0) return false;var v_values = Enum.GetValues(enumType).Cast<int>();if (v_values.Count() == 0) return false;v_values = v_values.Where(val => enumRangeAttribute.mEnumValues.Contains(val));if (v_values.Count() == 0) return false;var v_names = v_values.Select(val => Enum.GetName(enumType, val));if (v_names.Count() == 0) return false;displayNames = v_names.ToArray();return true;}// 返回指定名称的枚举在原始枚举合集中的索引private int IndexOf(string enumName){int index = Array.FindIndex(rawEnumNames, n => n.Equals(enumName));return index == -1 ? 0 : index;}
}

效果截图

 如果这篇文章对你有帮助,请给作者点个赞吧!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThreeWayBranch 优化阅读笔记

1. 优化目的 通过重排三分支的 BB 块减少比较指令的执行次数 代码路径: bolt/lib/Passes/ThreeWayBranch.cpp2. 效果 优化前&#xff1a; 注&#xff1a; 黄色数字表示BB块编号&#xff0c; 紫色表示该分支跳转的次数&#xff0c;绿色是代码里BB块的变量名 ThreeWayBranc…

精读《React Conf 2019 - Day2》

1 引言 这是继 精读《React Conf 2019 - Day1》 之后的第二篇&#xff0c;补充了 React Conf 2019 第二天的内容。 2 概述 & 精读 第二天的内容更为精彩&#xff0c;笔者会重点介绍比较干货的部分。 Fast refresh Fast refresh 是更好的 react-hot-loader 替代方案&am…

Spring Cloud Alibaba微服务从入门到进阶(二)

Spring Boot配置管理 1、application.properties 2、application.yml 1.内容格式比较&#xff1a; .properties文件&#xff0c;通过 . 来连接&#xff0c;通过 来赋值&#xff0c;结构上&#xff0c;没有分层的感觉&#xff0c;但比较直接。 .yml文件&#xff0c;通过 &…

Jade 处理XRD并计算半峰宽FWHM、峰面积、峰强度等数据

1.打开软件 2.导入测试的XRD数据 3.平滑数据 4.抠一下基底 5.分析具体数据 6.按住鼠标左键&#xff0c;在峰底部拉一条线&#xff0c;尽量和基底持平 7.结果就出来了&#xff0c;想要的都在里面&#xff0c;直接取值就行

初级爬虫实战——伯克利新闻

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

Linux命令深入学习——列出帮助手册,开机关机

linux中有多种方法查看一个不熟悉命令的详细信息&#xff0c;如 ls --help&#xff0c;help ls&#xff0c;man ls&#xff0c;info ls 在linux系统中可以使用命令进行开关机以及相关基础操作 同时在进行写入操作时&#xff0c;可以使用快捷键进行操作

Linux文件与文件系统的压缩

文章目录 Linux文件与文件系统的压缩Linux系统常见的压缩命令gzip&#xff0c;zcat/zmore/zless/zgrepbzip2&#xff0c;bzcat/bzmore/bzless/bzgreppxz&#xff0c;xzcat/xzmore/xzless/xzgrepgzip&#xff0c;bzip2&#xff0c;xz压缩时间对比打包命令&#xff1a;tar打包命令…

马斯克放出豪言,他旗下的xAI要把Grok开源了

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Halcon 使用光流算子检测运动物体

文章目录 算子optical_flow_mg 计算两个图像之间的光流vector_field_length 计算向量场的向量长度select_shape_std 选择给定形状的区域vector_field_to_real 将矢量场图像转换为两个实值图像intensity 计算灰度值的均值和偏差local_max_sub_pix 以亚像素精度检测局部极大值 Ha…

LVS负载均衡群集之NAT与DR模式

一 集群和分布式 企业群集应用概述 群集的含义 Cluster&#xff0c;集群、群集 由多台主机构成&#xff0c;但对外只表现为一个整体&#xff0c;只提供一个访问入口(域名或IP地址)&#xff0c;相当于一台大型计算机。 问题&#xff1f; 互联网应用中&#xff0c;随着站点对…

JVM优化

Java编码执行流程图 a.java ->javac&#xff08;前端编译器&#xff0c;javac属于其中一种&#xff09; ->a.class 和java类库 ->classloader-> Java解释器(一行行解释并运行) 或即时编译器JIT(Just In Time&#xff0c;属于后端编译器)JIT可以将一个方法&#xff…

SpringBoot多数据源切换 多数据源事务解决方案 二

https://zhuanlan.zhihu.com/p/612825647?utm_id0 https://blog.csdn.net/guzhangyu12345/article/details/108559810 SpringBoot多数据源事务解决方案 https://blog.csdn.net/u013407099/article/details/124526396多数据源切换下保证事务解决方案 https://blog.csdn.net/re…

郑州大学2024年3月acm实验室招新赛题解(A-L)

这里感谢一下计算机学术交流协会会长&#xff0c;acm实验室的中坚成员&#xff0c;以及本次比赛的出题人之一孙昱涵将他的账号借给了我。 回顾一下的话&#xff0c;这场的难度其实不是很大&#xff0c;不过对招新的新手来说难度还是挺大的。去掉签到都没签出来的选手的话&…

【C++ Primer Plus学习记录】第6章复习题

1.请看下面两个计算空格和换行符数目的代码片段&#xff1a; //Version 1 while(cin.get(ch)) //quit on eof,EOF(检测文件尾) { if(ch )spaces;if(ch \n)newlines; }//Version 2 while(cin.get(ch)) //quit on eof { if(ch )spaces;else if(ch \n)newlines; } 第…

C++_异常

目录 1、异常的关键字 2、异常的写法 3、异常的使用规则 3.1 规则1 3.2 规则2 3.3 规则3 3.4 规则4 3.5 规则5 4、异常的重新抛出 5、异常的规范 5.1 C98的异常规范 5.2 C11的异常规范 6、C标准库的异常体系 7、异常的优缺点 结语 前言&#xff1a; C的异常…

学习数据节构和算法的第15天

单链表的实现 链表的基本结构 #pragma once #include<stdio.h> typedf int SLTDataType; typedy struct SListNode {SLTDataType data;struct SListNode*next; }SLTNode;void Slisprint(SLTNode*phead);打印链表 #include<stdio.h> void SListPrint(SLTNode*phe…

详解DSLS达索许可管理器的安装与配置

DSLS的安装与配置 一、DSLS下载二、安装DLS三、使用DSLS四、更改计算机ID五、部分常见DSLS相关问题 一、DSLS下载 下载地址&#xff1a;https://software.3ds.com/?ticketST-5190987-dUM0dflc6zfjf04F5EXx-cas 注意&#xff1a;需要一个注册了的达索账号才能登录进去下载 一…

飞塔防火墙开局百篇——002.FortiGate上网配置——透明模式配置(Transparent)

透明模式配置 开启透明模式创建策略 在不改变现有网络拓扑前提下&#xff0c;将防火墙NGFW以透明模式部署到网络中&#xff0c;放在路由器和交换机之间&#xff0c;防火墙为透明模式&#xff0c;对内网网段192.168.1.0/24的上网进行4~7层的安全防护。 登陆FortiGate防火墙界面&…

24.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-根据配置文件自动生成C语言头文件

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;23.实现配置工具…

【infiniband监控】grafana变量使用细化优化监控指标

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…