using System; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; namespace HK.PropertyAttribute { #if UNITY_EDITOR [CustomPropertyDrawer(typeof(FilePathAttribute))] public class FilePathDrawer : PropertyDrawer { private string[] _filePaths; private string[] _displayNames; private int _selectedIndex = -1; private bool _isInitialized = false; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // 只处理字符串类型字段 if (property.propertyType != SerializedPropertyType.String) { EditorGUI.LabelField(position, label.text, "仅支持字符串类型字段"); return; } var attribute = (FilePathAttribute)base.attribute; // 初始化文件列表 if (!_isInitialized) { InitializeFileList(attribute, property.stringValue); _isInitialized = true; } // 绘制标签和下拉框 Rect labelRect = new Rect(position.x, position.y, EditorGUIUtility.labelWidth, position.height); Rect fieldRect = new Rect(position.x + EditorGUIUtility.labelWidth, position.y, position.width - EditorGUIUtility.labelWidth, position.height); EditorGUI.LabelField(labelRect, label); // 绘制下拉选择框 int newIndex = EditorGUI.Popup(fieldRect, _selectedIndex, _displayNames); if (newIndex != _selectedIndex && newIndex >= 0 && newIndex < _filePaths.Length) { _selectedIndex = newIndex; property.stringValue = _filePaths[newIndex]; property.serializedObject.ApplyModifiedProperties(); } } /// /// 初始化文件列表 /// private void InitializeFileList(FilePathAttribute attribute, string currentValue) { try { // 解析根路径(支持特殊路径) string rootPath = ResolvePath(attribute.RootPath); if (!Directory.Exists(rootPath)) { _displayNames = new[] { $"路径不存在: {rootPath}" }; _filePaths = new[] { "" }; _selectedIndex = 0; return; } // 获取所有文件 string[] allFiles = Directory.GetFiles(rootPath, "*.*", SearchOption.AllDirectories); // 筛选文件扩展名 if (!string.IsNullOrEmpty(attribute.FileExtensions)) { var extensions = attribute.FileExtensions .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(ext => ext.Trim().ToLower()).ToList(); allFiles = allFiles.Where(file => extensions.Contains(Path.GetExtension(file).ToLower())).ToArray(); } // 处理显示名称(相对路径) _filePaths = allFiles; _displayNames = allFiles.Select(file => GetRelativePath(rootPath, file)).ToArray(); // 找到当前值的索引 _selectedIndex = Array.IndexOf(_filePaths, currentValue); // 如果当前值不在列表中,默认选中第一个 if (_selectedIndex == -1 && _filePaths.Length > 0) { _selectedIndex = 0; } } catch (Exception ex) { _displayNames = new[] { $"错误: {ex.Message}" }; _filePaths = new[] { "" }; _selectedIndex = 0; } } /// /// 解析特殊路径 /// private string ResolvePath(string path) { if (path.StartsWith("Application.dataPath")) { return path.Replace("Application.dataPath", Application.dataPath); } else if (path.StartsWith("Application.streamingAssetsPath")) { return path.Replace("Application.streamingAssetsPath", Application.streamingAssetsPath); } else if (path.StartsWith("Application.persistentDataPath")) { return path.Replace("Application.persistentDataPath", Application.persistentDataPath); } else if (path.StartsWith("Application.temporaryCachePath")) { return path.Replace("Application.temporaryCachePath", Application.temporaryCachePath); } // 相对路径转为绝对路径 if (!Path.IsPathRooted(path)) { return Path.Combine(Application.dataPath, path); } return path; } /// /// 获取相对路径(用于显示) /// private string GetRelativePath(string rootPath, string fullPath) { Uri rootUri = new Uri(rootPath + Path.DirectorySeparatorChar); Uri fullUri = new Uri(fullPath); return rootUri.MakeRelativeUri(fullUri).ToString().Replace('/', Path.DirectorySeparatorChar); } } #endif }