UGUI一键刷新(创建)图集、自动生成图集

UI目录

目录结构.png
两个自定义类
#if UNITY_EDITOR

//Debug.Log(Regex.IsMatch(path, "Assets/UI/Modules/.[a-zA-Z0-9]*/Images/.[a-zA-Z0-9]*/.[^/]*.png"));
//Debug.Log(Regex.IsMatch(path, "Assets/UI/Modules/.[^/]*/Images/.[^/]*/.[^/]*.png"));

/// <summary>
/// 图片路径
/// </summary>
public class SpriteTemp
{
    /// <summary>
    /// 图片是不是UI模块
    /// </summary>
    public bool isUI;
    /// <summary>
    /// 图片所在模块
    /// </summary>
    public string moduleName;
    /// <summary>
    /// 图片父路径
    /// </summary>
    public string parentPath;
    /// <summary>
    /// 图片所在的图集名
    /// </summary>
    public string atlasName;

    public SpriteTemp(string path)
    {
        path = path.Replace("\\", "/");
        string[] pathSplit = path.Split('/');
        if (pathSplit.Length == 7)
        {
            if (pathSplit[1].Equals("UI") && pathSplit[2].Equals("Modules") && pathSplit[4].Equals("Images") && pathSplit[6].Contains(".png"))
            {
                this.isUI = true;
                this.moduleName = pathSplit[3];
                this.parentPath = $"Assets/UI/Modules/{this.moduleName}/Images/{pathSplit[5]}";
                this.atlasName = $"Atlas_{this.moduleName}_{pathSplit[5]}.spriteatlas";
                return;
            }
        }
        this.isUI = false;
    }
}


/// <summary>
/// 一个路径是不是UIAtlas路径
/// </summary>
public class AtlasTemp
{
    public bool isAtlas;
    /// <summary>
    /// 图集所在模块名
    /// </summary>
    public string moduleName;
    /// <summary>
    /// 图集的父文件路径
    /// </summary>
    public string parentPath;
    /// <summary>
    /// 图集的名字
    /// </summary>
    public string atlasName;

    public AtlasTemp(string path)
    {
        string[] pathSplit = path.Split('/');
        if (pathSplit.Length == 6)
        {
            if (pathSplit[1].Equals("UI") && pathSplit[2].Equals("Modules") && pathSplit[4].Equals("Images"))
            {
                this.isAtlas = true;
                this.moduleName = pathSplit[3];
                this.parentPath = $"Assets/UI/Modules/{this.moduleName}/Images/{pathSplit[5]}";
                this.atlasName = $"Atlas_{this.moduleName}_{pathSplit[5]}.spriteatlas";
                return;
            }
        }
        this.isAtlas = false;
    }
}



#endif
监听资源导入
using UnityEngine;
using UnityEditor;

public class AssetImportEditor : AssetPostprocessor
{

    //这里要重新整理,把删除、移动、添加的方法拆分开
    public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssets)
    {
        //Debug.Log("OnPostprocessAllAssets");

        foreach (string assetPath in importedAssets)
        {
            Debug.Log("导入资源 : " + assetPath);
        }

        ImportSpriteEditor.DeletedSprite(deletedAssets);
        ImportSpriteEditor.MoveSprite(movedAssets, movedFromAssets);

    }

    //--导入贴图前
    public void OnPreprocessTexture()
    {
        Debug.Log("导入贴图前 OnPreprocessTexture");
        ImportSpriteEditor.TextureToSprite(assetPath, assetImporter);
    }

    //--导入精灵后
    public void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
    {
        Debug.Log("导入精灵后 " + assetPath);
        AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceSynchronousImport);

        ImportSpriteEditor.AddSprites(assetPath, texture);

    }

    //--导入贴图后
    public void OnPostprocessTexture(Texture2D texture2D)
    {
        //Debug.Log("导入贴图后 OnPostprecessTexture");
    }
    public void OnPreprocessAudio()
    {
        Debug.Log("导入声音前 OnPreprocessAudio");
        AudioImporter audioImporter = (AudioImporter)assetImporter;
        Debug.Log(string.Format("路径 :{0}", audioImporter.assetPath));
    }
    //--导入声音后
    public void OnPostprocessAudio(AudioClip clip)
    {
        Debug.Log("导入声音后 OnPostprocessAudio");
    }

    //--导入模型前
    public void OnPreprocessModel()
    {
        Debug.Log("导入模型前 OnPreprocessModel");
        ModelImporter modelImporter = (ModelImporter)assetImporter;
    }

    //--导入模型后
    public void OnPostprocessModel(GameObject gameObject)
    {
        Debug.Log("导入模型后 OnPostprocessModel");
    }

    //--导入动画前
    public void OnPreprocessAnimation()
    {
        Debug.Log("导入动画前 OnPreprocessAnimation");
        ModelImporter modelImporter = (ModelImporter)assetImporter;
    }
    //--导入动画后
    public void OnPostprocessAnimation(GameObject gameObject, AnimationClip animationClip)
    {
        Debug.Log("导入动画后 OnPostprocessAnimation");
    }

    //--导入材质后
    public void OnPostprocessMaterial(Material material)
    {
        Debug.Log("导入材质后 OnPostprocessMaterial");
    }

}

检查是否是UGUI模块
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class ImportSpriteEditor : Editor
{
    static SpriteTemp add_sprite_temp = null;
    static Dictionary<string, SpriteTemp> deleted_sprite_refresh = new Dictionary<string, SpriteTemp>();
    static Dictionary<string, SpriteTemp> move_sprite_refresh = new Dictionary<string, SpriteTemp>();

    public static void TextureToSprite(string assetPath, AssetImporter assetImporter)
    {
        SpriteTemp spriteTemp = new SpriteTemp(assetPath);
        if (spriteTemp.isUI)
        {
            //是UI模块
            TextureImporter textureImporter = (TextureImporter)assetImporter;
            textureImporter.alphaSource = TextureImporterAlphaSource.FromInput;
            textureImporter.alphaIsTransparency = true;
            textureImporter.isReadable = false;
            textureImporter.textureCompression = TextureImporterCompression.Uncompressed;
            textureImporter.textureType = TextureImporterType.Sprite;
            //textureImporter.spritePackingTag = $"UIAtlas_{atlasData.moduleName}_{atlasData.fileName}";
            textureImporter.SaveAndReimport();
            TextureImporterPlatformSettings platformSetting = new TextureImporterPlatformSettings()
            {
                maxTextureSize = 1024,
                resizeAlgorithm = TextureResizeAlgorithm.Bilinear,
                format = TextureImporterFormat.Automatic,
                textureCompression = TextureImporterCompression.Compressed,
                crunchedCompression = false
            };
            textureImporter.SetPlatformTextureSettings(platformSetting);
        }
    }

    public static void AddSprites(string assetPath, Texture2D texture)
    {
        add_sprite_temp = null;
        SpriteTemp spriteTemp = new SpriteTemp(assetPath);
        if (spriteTemp.isUI)
        {
            Debug.Log($"添加UI : {assetPath}");
            add_sprite_temp = spriteTemp;

            //int value1 = texture.width % 4;
            //int value2 = texture.height % 4;
            //if (value1 != 0 || value2 != 0)
            //{
            //    Debug.LogError($"图片不符合规范,纹理的长宽都是4的倍数,才能被压缩成DXT5格式,图片位置:{assetPath}");
            //}
        }
        EditorApplication.delayCall += onDelayCalls_Add;
    }

    static void onDelayCalls_Add()
    {
        if (add_sprite_temp != null)
        {
            AtlasEditor.RefreshSpriteAtlas(add_sprite_temp.parentPath, add_sprite_temp.atlasName);
        }
        EditorApplication.delayCall -= onDelayCalls_Add;
    }

    public static void DeletedSprite(string[] assetPaths)
    {
        if (assetPaths.Length <= 0) return;
        deleted_sprite_refresh.Clear();
        for (int i = 0; i < assetPaths.Length; i++)
        {
            SpriteTemp spriteTemp = new SpriteTemp(assetPaths[i]);
            if (spriteTemp.isUI && deleted_sprite_refresh.ContainsKey(spriteTemp.parentPath) == false)
            {
                deleted_sprite_refresh.Add(spriteTemp.parentPath, spriteTemp);
            }
        }
        EditorApplication.delayCall += onDelayCalls_Deleted;
    }
    static void onDelayCalls_Deleted()
    {
        foreach (var item in deleted_sprite_refresh)
        {
            SpriteTemp spriteTemp = item.Value;
            AtlasEditor.RefreshSpriteAtlas(spriteTemp.parentPath, spriteTemp.atlasName);
        }
        EditorApplication.delayCall -= onDelayCalls_Deleted;
    }

    public static void MoveSprite(string[] movedAssets, string[] movedFromAssets)
    {
        if (movedAssets.Length <= 0) return;
        move_sprite_refresh.Clear();
        for (int i = 0; i < movedAssets.Length; i++)
        {
            string newPath = movedAssets[i];
            string oldPath = movedFromAssets[i];
            //刷新 oldPath Atlas 
            SpriteTemp old_spriteTemp = new SpriteTemp(oldPath);
            if (old_spriteTemp.isUI && move_sprite_refresh.ContainsKey(old_spriteTemp.parentPath) == false)
            {
                move_sprite_refresh.Add(old_spriteTemp.parentPath, old_spriteTemp);
            }
            //刷新 newPath Atlas
            SpriteTemp new_spriteTemp = new SpriteTemp(newPath);
            if (new_spriteTemp.isUI && move_sprite_refresh.ContainsKey(new_spriteTemp.parentPath) == false)
            {
                move_sprite_refresh.Add(new_spriteTemp.parentPath, new_spriteTemp);
            }
        }
        EditorApplication.delayCall += onDelayCalls_Move;
    }
    static void onDelayCalls_Move()
    {
        foreach (var item in move_sprite_refresh)
        {
            SpriteTemp spriteTemp = item.Value;
            AtlasEditor.RefreshSpriteAtlas(spriteTemp.parentPath, spriteTemp.atlasName);
        }
        EditorApplication.delayCall -= onDelayCalls_Move;
    }

}

创建图集
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;

public class AtlasEditor : Editor
{

    [MenuItem("Tools/刷新(创建)图集")]
    public static void onCreateAtlas()
    {
        string rootPath = Path.Combine(Application.dataPath, "UI/Modules");
        //获取文件夹下的一级子文件夹
        string[] allModule = Directory.GetDirectories(rootPath);
        foreach (string modulePath in allModule)
        {
            //模块下是否存在方图片的文件夹
            //Images下不允许直接方图片,需要放在Images的子文件夹中,如:Images/Common,Images/bg 等
            string imagesDire = Path.Combine(modulePath, "Images");
            bool isExists = Directory.Exists(imagesDire);
            if (isExists)
            {
                string[] allImagesDire = Directory.GetDirectories(imagesDire);
                foreach (string imageDire in allImagesDire)
                {
                    string direPath = "Assets" + imageDire.Substring(Application.dataPath.Length);
                    direPath = direPath.Replace("\\", "/");
                    AtlasTemp atlasTemp = new AtlasTemp(direPath);
                    if (atlasTemp.isAtlas)
                    {
                        RefreshSpriteAtlas(atlasTemp.parentPath, atlasTemp.atlasName);
                    }
                }
            }
        }
    }


    public static void RefreshSpriteAtlas(string parentPath, string atlasName)
    {
        Debug.Log("RefreshSpriteAtlas  " + parentPath);
        string atlasPath = $"{parentPath}/{atlasName}";

        _ClearSpriteAtlas(parentPath, atlasName);

        SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath);

        string[] spritePathArr = Directory.GetFiles(parentPath, "*.png");

        if (spritePathArr.Length <= 0)
        {
            if (atlas != null)
            {
                AssetDatabase.DeleteAsset(atlasPath);
            }
            return;
        }

        if (atlas == null)
        {
            _isCreateSpriteAtlas(atlasPath, spritePathArr);
        }
        else
        {
            _isRefreshSpriteAtlas(atlas, spritePathArr);
        }

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    static void _isRefreshSpriteAtlas(SpriteAtlas atlas, string[] spritePathArr)
    {
        Dictionary<string, Sprite> keyValues = new Dictionary<string, Sprite>();
        for (int i = 0; i < spritePathArr.Length; i++)
        {
            string spritePath = spritePathArr[i].Replace("\\", "/");
            Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(spritePath);
            if (sprite != null)
            {
                string spriteName = Path.GetFileNameWithoutExtension(spritePath);
                keyValues.Add(spriteName, sprite);
            }
        }

        var spriteArr = SpriteAtlasExtensions.GetPackables(atlas);
        var SpriteAtlasExtensions_Type = typeof(SpriteAtlasExtensions);
        var RemoveAt = SpriteAtlasExtensions_Type.GetMethod("RemoveAt", BindingFlags.Static | BindingFlags.NonPublic);
        for (int i = spriteArr.Length - 1; i >= 0; i--)
        {
            if (spriteArr[i] == null)
            {
                RemoveAt.Invoke(null, new[] { atlas, (object)i });
            }
            else
            {
                string name = spriteArr[i].name;
                if (keyValues.ContainsKey(name))
                {
                    keyValues.Remove(name);
                }
                else
                {
                    RemoveAt.Invoke(null, new[] { atlas, (object)i });
                }
            }
        }
/*
        SerializedObject serializedObject = new SerializedObject(atlas);
        SerializedProperty packables = serializedObject.FindProperty("m_EditorData.packables");
        for (int i = packables.arraySize - 1; i >= 0; i--)
        {
            SerializedProperty texsp = packables.GetArrayElementAtIndex(i);
            string spritePath = texsp.objectReferenceValue != null ? AssetDatabase.GetAssetPath(texsp.objectReferenceValue) : string.Empty;
            //string spriteParent = string.IsNullOrEmpty(spritePath) ? string.Empty : Path.GetDirectoryName(spritePath).Replace("\\", "/");
            //if (string.IsNullOrEmpty(spriteParent) || spriteParent != atlasTemp.parentPath || keyValuePairs.ContainsKey(spritePath) == false)
            //{
            //    texsp.objectReferenceValue = null;
            //    packables.DeleteArrayElementAtIndex(i);
            //}
            if (!string.IsNullOrEmpty(spritePath) && keyValues.ContainsKey(spritePath))
            {
                keyValues.Remove(spritePath);
            }
            else
            {
                texsp.objectReferenceValue = null;
                packables.DeleteArrayElementAtIndex(i);
            }
        }
        serializedObject.ApplyModifiedProperties();
*/
        List<Sprite> spriteList = new List<Sprite>();
        foreach (var item in keyValues)
        {
            spriteList.Add(item.Value);
        }
        atlas.Add(spriteList.ToArray());

    }

    static void _isCreateSpriteAtlas(string atlasPath, string[] spritePathArr)
    {
        SpriteAtlas atlas = _CreateSpriteAtlas(atlasPath);
        List<Sprite> sprites = new List<Sprite>();
        for (int i = 0; i < spritePathArr.Length; i++)
        {
            string spritePath = spritePathArr[i].Replace("\\", "/");
            Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(spritePath);
            if (sprite != null)
            {
                sprites.Add(sprite);
            }
        }
        atlas.Add(sprites.ToArray());
/*
        //SerializedObject serializedObject = new SerializedObject(atlas);
        //SerializedProperty packables = serializedObject.FindProperty("m_EditorData.packables");
        //for (int i = 0; i < sprites.Count; i++)
        //{
        //    packables.InsertArrayElementAtIndex(i);
        //    packables.GetArrayElementAtIndex(i).objectReferenceValue = sprites[i];
        //}
        //serializedObject.ApplyModifiedProperties();
*/
    }

    static void _ClearSpriteAtlas(string parentPath, string atlasName)
    {
        string[] allAtlas = Directory.GetFiles(parentPath, "*.spriteatlas");
        foreach (string atlasPath in allAtlas)
        {
            //获取此文件夹下所有图集并删除不符合规范的图集
            string name = Path.GetFileName(atlasPath);
            if (atlasName.Equals(name) == false)
            {
                //删除不符合命名规范的图集
                AssetDatabase.DeleteAsset(atlasPath);
            }
        }
    }
    /// <summary>
    /// 创建一个图集
    /// </summary>
    /// <param name="atlasPath"></param>
    /// <returns></returns>
    static SpriteAtlas _CreateSpriteAtlas(string atlasPath)
    {
        SpriteAtlas atlas = new SpriteAtlas();
        //此选项为false时,需要手写atlas加载方法:SpriteAtlasManager.atlasRequested += void
        atlas.SetIncludeInBuild(true);
        SpriteAtlasPackingSettings packSetting = new SpriteAtlasPackingSettings()
        {
            blockOffset = 1,
            enableRotation = false,
            enableTightPacking = false,
            padding = 4,
        };
        atlas.SetPackingSettings(packSetting);
        SpriteAtlasTextureSettings textureSetting = new SpriteAtlasTextureSettings()
        {
            readable = false,
            generateMipMaps = false,
            sRGB = true,
            filterMode = FilterMode.Bilinear,
        };
        atlas.SetTextureSettings(textureSetting);
        AssetDatabase.CreateAsset(atlas, atlasPath);
        return atlas;
    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容