EditorUtility.DisplayCancelableProgressBar无法正常取消的问题
用到的API:
-
Directory.GetFiles() :返回符合指定条件的文件名链接
-
Path.GetExtension() :返回指定路径的扩展名链接
-
EditorUtility.DisplayCancelableProgressBar() :显示或更新含有 Cancel 按钮的进度条。链接
-
AssetDatabase.GetAssetPath() : 获取对象的路径; AssetDatabase.AssetPathToGUID() :通过路径获取对应的GUID ;AssetDatabase.LoadAssetAtPath() : 通过路径定位到资源位置。链接
额外扩展:
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
public static class FindUIReferences
{
private static MethodInfo clearConsole;
[MenuItem("Assets/Find UI References", false, 10)]
private static void Find()
{
EditorSettings.serializationMode = SerializationMode.ForceText;
var objects = Selection.objects;//获取所有选中的对象。
ClearConsole();//清除控制台中已有的Log日志。
var withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };// 所查找文件的后缀。
List<string> files = Directory.GetFiles(Application.dataPath + "/Bundles/UI", "*.*", SearchOption.AllDirectories).Where
(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToList();
files.AddRange
(
Directory.GetFiles(Application.dataPath + "/ArtsUI/UI", "*.*", SearchOption.AllDirectories).Where
(s => string.Equals(Path.GetExtension(s).ToLower(), ".spriteatlas")).ToList()
); // 所查找文件的路径。
bool clickCancelBtn = false;
bool cancel = false;//添加取消查找标志位,防止手动取消时无法取消 Ps:取消时没有正确退出While循环,导致update仍然继续运行。
int objectIndex = 0;
Dictionary<Object, int> objectFindCountDic = new Dictionary<Object, int>();
string redMessage = "<color=#FF0000>{0}</color>";
EditorApplication.update = delegate()//update回调,每帧执行查找操作。
{
while (objectIndex < objects.Length)
{
var tempObject = objects[objectIndex];
string path = AssetDatabase.GetAssetPath(tempObject);//通过对象获取路径;用于查找对象的GUID
int startIndex = 0;
if (!string.IsNullOrEmpty(path))
{
objectFindCountDic[tempObject] = 0;
string guid = AssetDatabase.AssetPathToGUID(path);//通过路径获取对应的GUID
while (startIndex < files.Count)
{
string file = files[startIndex];
clickCancelBtn = EditorUtility.DisplayCancelableProgressBar("匹配资源中", file, (float)startIndex / (float)files.Count);//创建带有取消功能的进度条。返回值为是否关闭进度条。
if (Regex.IsMatch(File.ReadAllText(file), guid))//正则表达式匹配
{
Debug.Log($"资源名称: {tempObject.name} ; 引用路径: {file}", AssetDatabase.LoadAssetAtPath<Object>(GetRelativeAssetsPath(file)));
objectFindCountDic[tempObject]++;
}
if (clickCancelBtn)
{
cancel = true;
break;
}
startIndex++;
}
}
objectIndex++;
if (cancel || objectIndex >= objects.Length)
{
EditorUtility.ClearProgressBar();//关闭进度条
EditorApplication.update = null;//update回调置空
startIndex = 0;
Debug.Log($"{(cancel? string.Format(redMessage, "手动取消匹配,匹配结束。") : "文件查找完成,匹配结束。")}");
foreach (KeyValuePair<Object, int> keyValuePair in objectFindCountDic)
{
string assetPath = AssetDatabase.GetAssetPath(keyValuePair.Key);
Debug.Log
(
$"资源名称:{keyValuePair.Key.name + Path.GetExtension(assetPath)};所匹配资源个数:{(keyValuePair.Value <= 0? string.Format(redMessage, keyValuePair.Value) : keyValuePair.Value)}",
AssetDatabase.LoadAssetAtPath<Object>(assetPath)
);// 添加:AssetDatabase.LoadAssetAtPath<Object>(assetPath) 使添加log时可以定位到对应的资源。
}
break;
}
}
};
}
private static void ClearConsole()
{
if (clearConsole == null)
{
//获取 UnityEditor.LogEntries 程序集中的Clear方法并调用。
var log = typeof (EditorWindow).Assembly.GetType("UnityEditor.LogEntries");
clearConsole = log.GetMethod("Clear");
}
clearConsole?.Invoke(null, null);
}
[MenuItem("Assets/Find References", true)]
private static bool VFind()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
return (!string.IsNullOrEmpty(path));
}
private static string GetRelativeAssetsPath(string path)
{
return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
}
}