//************************ // Create By 流云 // Time: 2025.01.15 // Desc: 设置图片资源组件 //************************ import { size, Size, Texture2D, UITransform, Vec2 } from 'cc'; import { AssetManager } from 'cc'; import { ImageAsset } from 'cc'; import { _decorator, assetManager, Component, Node, Sprite, SpriteFrame } from 'cc'; import MTools from '../tools/MTools'; const { ccclass, property, executeInEditMode } = _decorator; /** * 设置图片资源组件 */ @ccclass('SpriteLoad') //@executeInEditMode export class SpriteLoad extends Component { @property private bundleName: string = "icons"; @property({ type: Node }) private SpriteNode: Node = null; @property private AdaptSize: boolean = false; spComp: Sprite = null; path: string = ""; private _loadedRes = null; private _initSize: Size = null; private _curentPath = ""; onLoad() { this._initSize = this.node.getComponent(UITransform).contentSize.clone(); if (this.SpriteNode) { this.spComp = this.SpriteNode.getComponent(Sprite); } else { this.SpriteNode = this.node; this.spComp = this.getComponent(Sprite); } } protected onEnable(): void { // 取消隐藏时预约的释放,避免下一帧 clear 把刚 load 的图清掉(主界面子页 SetActive 切换常见) this.unschedule(this._deferredClear); if (this._curentPath != "") this.loadSprite(); } /** 与 onDestroy 共用同一引用,便于 unschedule */ private readonly _deferredClear = (): void => { if (!this.isValid || !this.node?.isValid) return; // 已重新显示则不再释放(与 onEnable 的 unschedule 双保险,避免同帧/排序边界误清) if (this.node.activeInHierarchy) return; this.clear(); }; protected onDisable(): void { // 关弹窗销毁时:同步 clear 可能与当帧 updateUVs 竞态;延后一帧释放。 // 主界面仅 SetActive(false) 隐藏时:若之后又显示,onEnable 会 unschedule;若仍隐藏则下一帧再释放引用。 this.scheduleOnce(this._deferredClear, 0); } protected onDestroy(): void { this.unschedule(this._deferredClear); this.clear(); } /** * 清除图片 */ clear() { if (this.path != "" && this._loadedRes) { this._loadedRes.decRef(); this._loadedRes = null; if (this.spComp?.spriteFrame) { this.spComp.spriteFrame = null; } } } /** * 设置图片 * @param path 图片路径(传空则清除当前的图片) * @param bundleName 资源包名 * @returns */ setSprite(path: string, bundleName: string = "", callback = null) { if (this.spComp == null) return; if (bundleName != "") { this.bundleName = bundleName; } this.path = path; let name = path.split("/").pop(); if (this.bundleName == "" || this.path == "") { return; } // this.spComp.spriteFrame = gg.res.getRes(name, this.path, this.bundleName, SpriteFrame); // return; this.path += "/spriteFrame"; if (this._curentPath != "" && this._curentPath == this.path && this._loadedRes && this.spComp.spriteFrame) return; //this.clear(); // this.scheduleOnce(() => { // this.loadSprite(callback); // }, 0.1); this.loadSprite(callback); } /** * 加载远程图片 * @param url 远程url */ loadRemote(url: string) { if (this.spComp == null) return; if (this.hasImageExtension(url)) this.loadTexture(url); else this.loadTextureExt(url); } private loadSprite(callback = null) { this.loadBundle((bundle: AssetManager.Bundle) => { let res = bundle.get(this.path, SpriteFrame); if (res) { if (this.node && this.node.isValid && this.spComp) { this.spComp.spriteFrame = res; this._curentPath = this.path; res.addRef(); this._loadedRes = res; } this.adoptSize(); return; } bundle.load(this.path, SpriteFrame, (err, sp) => { if (err) { console.log(err); //重新加载 if (callback) { callback(false); } return; } if (this.node && this.node.isValid && this.spComp) { this.spComp.spriteFrame = sp; this._curentPath = this.path; this._loadedRes = sp; this._loadedRes.addRef(); } if (callback) { callback(true); } this.adoptSize(); }); }); } private loadBundle(callback) { let bundle = assetManager.getBundle(this.bundleName); if (bundle) { callback(bundle); return; } assetManager.loadBundle(this.bundleName, (err, bundle) => { if (err) { console.log(err); return; } callback(bundle); }); } private loadTexture(url: string) { //let remoteUrl = "http://unknown.org/someres.png"; assetManager.loadRemote(url, (err, imageAsset) => { if (err) { console.log(`远程加载图片${url}出错--err:` + err); return; } let spriteFrame = new SpriteFrame(); let texture = new Texture2D(); texture.image = imageAsset; spriteFrame.texture = texture; this.spComp.spriteFrame = spriteFrame; }); } private loadTextureExt(url: string, ext: string = ".png") { // 远程 url 不带图片后缀名,此时必须指定远程图片文件的类型 //remoteUrl = "http://unknown.org/emoji?id=124982374"; assetManager.loadRemote(url, { ext: ext }, (err, imageAsset) => { if (err) { console.log(`远程加载图片${url}出错--err:` + err); return; } let spriteFrame = new SpriteFrame(); let texture = new Texture2D(); texture.image = imageAsset; spriteFrame.texture = texture; this.spComp.spriteFrame = spriteFrame; }); } /** * 判断图片url是否带后缀 * @param url * @returns */ private hasImageExtension(url: string): boolean { // 正则表达式匹配常见的图片后缀名 let imageExtensionPattern = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i; return imageExtensionPattern.test(url); } private adoptSize() { if (this.spComp == null) return; if (this.spComp.spriteFrame == null) return; let spriteFrame = this.spComp.spriteFrame; let width = spriteFrame.originalSize.width; let height = spriteFrame.originalSize.height; if (this.AdaptSize) { let s = MTools.adaptSize(this._initSize.width, this._initSize.height, width, height); this.node.getComponent(UITransform).contentSize = size(s.x, s.y); } } }