UIMgr.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { IUIItem } from './UIDef';
  2. const { ccclass, property } = cc._decorator;
  3. enum UILoadingState {
  4. none,
  5. loading,
  6. show,
  7. close,
  8. };
  9. class UILoadingHandle {
  10. private static _idBase = 0;
  11. private _instId: number = 0;
  12. constructor(){
  13. this._instId = UILoadingHandle._idBase++;
  14. }
  15. public get instId(): number {
  16. return this._instId;
  17. }
  18. state: UILoadingState = UILoadingState.loading;
  19. asset: cc.Asset;
  20. node: cc.Node;
  21. uiData: IUIItem;
  22. destory(){
  23. if(cc.isValid(this.node, true)) {
  24. this.node.destroy();
  25. }
  26. this.asset && this.asset.decRef();
  27. this.state = UILoadingState.close;
  28. }
  29. }
  30. /**
  31. * @en the `User Interface Manager`, handles some stuffs like the ui loads,ui layers,resizing etc.
  32. * @zh UI管理器,处理UI加载,层级,窗口变化等
  33. *
  34. * */
  35. export class UIMgr {
  36. private static _inst: UIMgr;
  37. public static get inst(): UIMgr {
  38. if (this._inst == null) {
  39. this._inst = new UIMgr();
  40. }
  41. return this._inst;
  42. }
  43. private _uiCanvas: cc.Node;
  44. private _uiRoot: cc.Node;
  45. handleArr:UILoadingHandle[] = []; // 允许打开两个相同的界面
  46. private createFullScreenNode() {
  47. let canvas = this._uiCanvas;
  48. let node = new cc.Node();
  49. node.group = this._uiCanvas.group;
  50. node.width = canvas.width;
  51. node.height = canvas.height;
  52. let widget = node.addComponent(cc.Widget);
  53. widget.isAlignBottom = true;
  54. widget.isAlignTop = true;
  55. widget.isAlignLeft = true;
  56. widget.isAlignRight = true;
  57. widget.left = 0;
  58. widget.right = 0;
  59. widget.top = 0;
  60. widget.bottom = 0;
  61. return node;
  62. }
  63. /**
  64. * @en setup this UIMgr,`don't call more than once`.
  65. * @zh 初始化UIMgr,`不要多次调用`
  66. * */
  67. public setup(uiCanvas: cc.Node | cc.Prefab, maxLayers: number, layerNames?: Array<string>) {
  68. if (this._uiCanvas) {
  69. return;
  70. }
  71. if (!uiCanvas) {
  72. cc.error('uiCanvas must be a cc.Node or cc.Prefab');
  73. return;
  74. }
  75. if (uiCanvas instanceof cc.Node) {
  76. this._uiCanvas = uiCanvas;
  77. }
  78. else {
  79. this._uiCanvas = cc.instantiate(uiCanvas);
  80. cc.director.getScene().addChild(this._uiCanvas);
  81. }
  82. this._uiCanvas.name = '$tgxUICanvas$';
  83. layerNames ||= [];
  84. this._uiRoot = this.createFullScreenNode();
  85. this._uiRoot.name = 'ui_root'
  86. this._uiCanvas.addChild(this._uiRoot);
  87. //create layers
  88. for (let i = 0; i < maxLayers; ++i) {
  89. let layerNode = this.createFullScreenNode();
  90. layerNode.name = 'ui_layer_' + (layerNames[i] ? layerNames[i] : i);
  91. this._uiRoot.addChild(layerNode);
  92. layerNode.on(cc.Node.EventType.CHILD_REMOVED, this.uiRemove, this);
  93. }
  94. }
  95. private uiRemove(node: cc.Node){
  96. let index = this.handleArr.findIndex((v)=>{
  97. return v.node.uuid == node.uuid;
  98. });
  99. if(index != -1) {
  100. this.hideUIIndex(index);
  101. }
  102. }
  103. public getLayerNode(layerIndex: number): cc.Node {
  104. return this._uiRoot.children[layerIndex] || this._uiRoot;
  105. }
  106. public getUI(uiData: IUIItem): UILoadingHandle {
  107. return this.handleArr.find((v)=>{return v.uiData.prefab == uiData.prefab});
  108. }
  109. public isShowing(uiData: IUIItem): boolean {
  110. let find = this.getUI(uiData);
  111. if(!find) return false;
  112. return find.state == UILoadingState.loading || find.state == UILoadingState.show;
  113. }
  114. public showUI(uiData: IUIItem) {
  115. let handle = new UILoadingHandle();
  116. handle.state = UILoadingState.loading;
  117. handle.uiData = uiData;
  118. this.handleArr.push(handle);
  119. cc.resources.load(uiData.prefab, cc.Prefab, (err, res)=>{
  120. if(err){
  121. console.log(err);
  122. this.showUI(uiData);
  123. return;
  124. }
  125. if(handle.state == UILoadingState.loading){
  126. let node = cc.instantiate(res);
  127. let layer = this.getLayerNode(uiData.layer);
  128. layer.addChild(node);
  129. handle.state = UILoadingState.show;
  130. handle.asset = res;
  131. handle.node = node;
  132. res.addRef();
  133. }
  134. else{
  135. cc.assetManager.releaseAsset(res);
  136. }
  137. })
  138. return handle;
  139. }
  140. //注:同一个prefab可能会有多个实例,只有一个实例时调用。
  141. public hideUI(uiData: IUIItem){
  142. let index = this.handleArr.findIndex((v)=>{return v.uiData.prefab == uiData.prefab});;
  143. if(index==-1) return;
  144. this.hideUIIndex(index);
  145. }
  146. public hideUIIndex(index: number){
  147. let find = this.handleArr[index];
  148. find.destory();
  149. this.handleArr.splice(index, 1);
  150. }
  151. }
  152. window['uiMgr'] = function(){
  153. return UIMgr.inst;
  154. }