Unity编辑器拓展之十五:NGUI批量替换图集工具

本文介绍了一款用于Unity项目的UI换肤工具,该工具能够批量替换预制体中的图集资源,便于快速预览不同皮肤的效果。通过简单的几步操作,即可完成图集的替换工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博客迁移

个人博客站点,欢迎访问,www.jiingfengji.tech

NGUI批量替换图集工具

工具目的

因项目需要实现换肤的功能,也就是多套UI图集,提供工具批量换图集,方便查看Prebab各皮肤(图集)下的效果

示意图

Gif 操作动图:
这里写图片描述

工具截图:
这里写图片描述

工具左侧是工程所有Prefab列表,右侧是替换图集的功能菜单,从指定原图集替换成目标图集

逻辑

与上文:Unity编辑器之十四:字体替换工具 https://blog.youkuaiyun.com/qq_26999509/article/details/81106083 一样,其实找到Prebfab下所有UISprite,并将其所有指定原图集 替换成 指定的目标图集,以此实现换肤的功能,当然两图集的SpriteName应该保持一致,不然没办法知道要换成目标图集里的那张图。

重点代码

private void ReplacePrefabAtalas(GameObject prefab , UIAtlas atlas,UIAtlas targetAtlas)
{
	if(prefab == null || atlas == null) return;
	UISprite[] sprites = prefab.GetComponentsInChildren<UISprite>(true);
	if(sprites != null && sprites.Length > 0)
	{
		int num = sprites.Length;
		for (int i = 0; i < num; i++)
		{
			UISprite s = sprites[i];
			if(s != null && s.atlas == atlas)
			{
				s.atlas = targetAtlas;
				EditorUtility.SetDirty(s);
			}
		}
	}
	AssetDatabase.SaveAssets();
}

使用

1、Tools->ReplaceAtalas 打开工具

这里写图片描述

2、选中待处理预制体,鼠标右键->替换图集

这里写图片描述

3、
这里写图片描述

4、这里写图片描述

工具代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditor.IMGUI.Controls;

public class ReplaceAtalas : EditorWindow 
{

	private static ReplaceAtalas window = null;
	private static List<string> prefabPathList = new List<string> ();
	private static string assetPath;

	Rect SearchFieldRect
	{
		get
		{
			return new Rect(interval,interval,position.width * 0.3f,20f);
		}
	}

	Rect prefabListRect 
	{
        get { return new Rect (interval, interval + SearchFieldRect.yMax, SearchFieldRect.width, window.position.height - SearchFieldRect.yMax - 2 * interval); }
    }

	Rect replaceAtalsRect
	{
		get{return new Rect(prefabListRect.xMax + interval,interval,window.position.width - SearchFieldRect.width - 3 * interval,window.position.height - 2 * interval);}
	}

	private Vector2 scrollWidgetPos;
	private float interval = 20f;
	private string searchStr = "";
	private SearchField searchField;
	private bool initialized = false;

	[MenuItem("Assets/替换图集", false, 2001)]
	public static void OpenWindow()
	{
		string selectedAssetPath = AssetDatabase.GetAssetPath (Selection.activeObject);
		if(!string.IsNullOrEmpty(selectedAssetPath) && selectedAssetPath.EndsWith(".prefab"))
		{
			ReplaceAtalas window = ShowWindow();
			if(window != null)
			{
				window.AutoSelctPrefab(selectedAssetPath);
			}
		}
	}

	[MenuItem("Tools/ReplaceAtalas")]
	public static ReplaceAtalas ShowWindow() 
	{
		prefabPathList.Clear ();
        assetPath = Application.dataPath;
        GetFiles (new DirectoryInfo (assetPath), "*.prefab", ref prefabPathList);
		if (window == null)
			window = EditorWindow.GetWindow(typeof(ReplaceAtalas)) as ReplaceAtalas;
		window.titleContent = new GUIContent("ReplaceAtalas");
		window.Show();
		return window;
	}

	public static void GetFiles (DirectoryInfo directory, string pattern, ref List<string> fileList) 
	{
        if (directory != null && directory.Exists && !string.IsNullOrEmpty (pattern)) {
            try {
                foreach (FileInfo info in directory.GetFiles (pattern)) {
                    string path = info.FullName.ToString ();
                    fileList.Add (path.Substring (path.IndexOf ("Assets")));
                }
            } catch (System.Exception) 
			{
                throw;
            }
            foreach (DirectoryInfo info in directory.GetDirectories ()) 
			{
                GetFiles (info, pattern, ref fileList);
            }
        }
    }

	private void OnGUI() 
	{
		InitIfNeeded();
		DrawWindow();
	}

	private void DrawWindow()
	{
		DrawSearchField();
		DrawPrefabList();
		DrawReplaceAtalasTool();
	}

	private void InitIfNeeded()
	{
		if(!initialized)
		{
			if (null == searchField)
            	searchField = new SearchField ();
		}
        initialized = true;
	}

	private void DrawSearchField()
	{
		GUI.backgroundColor = Color.white;
		searchStr = searchField.OnGUI (SearchFieldRect, searchStr);
		searchStr = searchStr.ToLower();
	}

	private void DrawPrefabList()
	{
		GUI.backgroundColor = Color.white;
			
		GUI.Box(prefabListRect,"");
		GUILayout.BeginArea(prefabListRect);
		scrollWidgetPos = EditorGUILayout.BeginScrollView(scrollWidgetPos);
		for (int i = 0; i < prefabPathList.Count; i++)
		{
			if(CheckShowPrefab(prefabPathList[i],searchStr))
			{
				if(GUILayout.Button(prefabPathList[i]))
				{
					curReplacePrefabPath = prefabPathList[i];
					curPrefabAtlas = GetPrefabAllAtlas(curReplacePrefabPath);
				}
			}
		}
		EditorGUILayout.EndScrollView();
		GUILayout.EndArea();
	}

	private string curReplacePrefabPath = "";

	private bool CheckShowPrefab(string path,string searchstr)
	{
		if(string.IsNullOrEmpty(searchStr)) return true;
		if(string.IsNullOrEmpty(path)) return false;
		return GetFileNameWithSuffix(path.ToLower()).Contains(searchStr);
	}

	//包括后缀名
	private string GetFileNameWithSuffix(string path)
	{
		if(string.IsNullOrEmpty(path)) return string.Empty;
		return path.Substring(path.LastIndexOf("/")+1);
	}

	private UIAtlas curAtlas;
	private UIAtlas targetAtlas;

	void OnSelectAtlas (Object obj)
	{
		UIAtlas atlas = obj as UIAtlas;
		if(isSelectCurAtlas)
		{
			curAtlas = obj as UIAtlas;
		}
		else if(isSelectTargetAtlas)
		{
			targetAtlas = obj as UIAtlas;
		}
		isSelectCurAtlas = false;
		isSelectTargetAtlas = false;
	}

	private bool isSelectCurAtlas = false;
	private bool isSelectTargetAtlas = false;
	private List<UIAtlas> curPrefabAtlas = new List<UIAtlas>();
	private void DrawReplaceAtalasTool()
	{
		GUI.backgroundColor = Color.white;
		
		GUILayout.BeginArea(replaceAtalsRect);
		EditorGUILayout.LabelField(curReplacePrefabPath);

		GUILayout.BeginHorizontal();
		EditorGUILayout.LabelField("该预制体含有的所有图集:",GUILayout.Width(150));
		if(curPrefabAtlas.Count > 0)
		{
			for (int i = 0; i < curPrefabAtlas.Count; i++)
			{
				if(GUILayout.Button(curPrefabAtlas[i].name))
				{
					curAtlas = curPrefabAtlas[i];
				}
				if(GUILayout.Button("Edit"))
				{
					//NGUISettings.atlas = mFont.atlas;
					//NGUISettings.selectedSprite = sym.spriteName;
					NGUIEditorTools.Select(curPrefabAtlas[i].gameObject);
				}
			}
		}
		GUILayout.EndHorizontal();

		//原图集
		GUILayout.BeginHorizontal();
		curAtlas = (UIAtlas)EditorGUILayout.ObjectField("被替换图集", curAtlas, typeof(UIAtlas), true);
		if (NGUIEditorTools.DrawPrefixButton("选择Atlas",GUILayout.Width(200)))
		{
			isSelectCurAtlas = true;
			ComponentSelector.Show<UIAtlas>(OnSelectAtlas);
		}
		GUILayout.EndHorizontal();

		//目标图集
		GUILayout.BeginHorizontal();
        targetAtlas = (UIAtlas)EditorGUILayout.ObjectField("目标图集", targetAtlas, typeof(UIAtlas), true);		
		
		if (NGUIEditorTools.DrawPrefixButton("选择Atlas",GUILayout.Width(200)))
		{
			isSelectTargetAtlas = true;
			ComponentSelector.Show<UIAtlas>(OnSelectAtlas);
		}
		GUILayout.EndHorizontal();

		if(GUILayout.Button("互换"))
		{
			UIAtlas tmpCurAtlas = curAtlas;
			curAtlas = targetAtlas;
			targetAtlas = tmpCurAtlas;
		}

		//替换按钮
		if(GUILayout.Button("替换图集"))
		{
			if(string.IsNullOrEmpty(curReplacePrefabPath))
			{
				EditorUtility.DisplayDialog("提示", "请先选择一个预制体!", "确定");
			}
			else if (curAtlas == null)
			{
				EditorUtility.DisplayDialog("提示", "请先指定被替换图集!", "确定");
			}
			else
			{
				if(targetAtlas == null)
				{
					if(EditorUtility.DisplayDialog("提示", "原图集将被清空,确定替换吗?", "确定","取消"))
					{
						ReplacePrefabAtalas(curReplacePrefabPath);
					}
				}
				else
				{
					ReplacePrefabAtalas(curReplacePrefabPath);
				}
			}
		}
		//保存按钮
		
		//撤销按钮

		GUILayout.EndArea();
	}

	private void ReplacePrefabAtalas(string path)
	{
		if(string.IsNullOrEmpty(path)) return;
		GameObject gameObj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
        ReplacePrefabAtalas(gameObj,curAtlas,targetAtlas);
	}	

	private List<UIAtlas> GetPrefabAllAtlas(string path)
	{
		if(string.IsNullOrEmpty(path)) return null;
		GameObject gameObj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
		return GetPrefabAllAtlas(gameObj);
	}

	private List<UIAtlas> GetPrefabAllAtlas(GameObject prefab)
	{
		if(null == prefab) return null;
		List<UIAtlas> atlass = new List<UIAtlas>();
		UISprite[] sprites = prefab.GetComponentsInChildren<UISprite>(true);
		if(sprites != null && sprites.Length > 0)
		{
			int num = sprites.Length;
			for (int i = 0; i < num; i++)
			{
				UISprite s = sprites[i];
				if(s != null && !atlass.Contains(s.atlas))
				{
					atlass.Add(s.atlas);
				}
			}
		}
		return atlass;
	}

	private void ReplacePrefabAtalas(GameObject prefab , UIAtlas atlas,UIAtlas targetAtlas)
	{
		if(prefab == null || atlas == null) return;
		UISprite[] sprites = prefab.GetComponentsInChildren<UISprite>(true);
		if(sprites != null && sprites.Length > 0)
		{
			int num = sprites.Length;
			for (int i = 0; i < num; i++)
			{
				UISprite s = sprites[i];
				if(s != null && s.atlas == atlas)
				{
					s.atlas = targetAtlas;
					EditorUtility.SetDirty(s);
				}
			}
		}
		AssetDatabase.SaveAssets();
	}

	public void AutoSelctPrefab(string prefabPath)
	{
		if(string.IsNullOrEmpty(prefabPath)) return;
		curReplacePrefabPath = prefabPath;
		curPrefabAtlas = GetPrefabAllAtlas(curReplacePrefabPath);
		curAtlas = null;
		targetAtlas = null;
	}
}

代码Git地址

https://github.com/JingFengJi/ReplaceAtlas
欢迎加星

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值