WindowSystem.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import { _decorator, Component, Constructor, find, Node, Prefab, instantiate, EventHandler, game } from "cc";
  2. import { ResourcesUtils } from "../../resourceManager/ResourcesUtils";
  3. import { Utils } from "../../utils/Utils";
  4. import { Tips } from "./Tips";
  5. import { Window } from "./Window";
  6. import { WindowOpenMode } from "./WindowOpenMode";
  7. const { ccclass, property } = _decorator;
  8. /**
  9. * 窗口系统,负责管理窗口,底层运行时自动创建,无需在编辑器中绑定
  10. * @author 袁浩
  11. */
  12. @ccclass('WindowSystem')
  13. export class WindowSystem extends Component {
  14. @property({ tooltip: "Canvas节点名称" })
  15. public canvasName = "Canvas";
  16. public windowList: Window[] = [];
  17. private static thisObject: WindowSystem;
  18. start() {
  19. game.addPersistRootNode(this.node);//常驻节点
  20. WindowSystem.thisObject = this;
  21. }
  22. public onWindowOpen(_window: Window) {
  23. this.windowList.push(_window);
  24. }
  25. public onWindowClose(_window: Window) {
  26. Utils.removeArrayItem(this.windowList, _window);
  27. }
  28. public static onWindowOpen(_window: Window) {
  29. this.thisObject.onWindowOpen(_window);
  30. }
  31. /**
  32. * 最近打开的窗口
  33. */
  34. public get currentWindow(): Window {
  35. return this.windowList[this.windowList.length - 1];
  36. }
  37. public destroyWindow(_window: Window) {
  38. for (let i = 0; i < _window.openWindowOnClosing.length; i++) {
  39. _window.openWindowOnClosing[i].emit([_window]);
  40. }
  41. if (_window.onClosing.length) {
  42. for (let i = 0; i < _window.onClosing.length; i++) {
  43. _window.onClosing[i].emit([() => {
  44. _window.node.destroy();
  45. Utils.removeArrayItem(this.windowList, _window);
  46. }]);
  47. }
  48. }
  49. else {
  50. _window.node.destroy();
  51. Utils.removeArrayItem(this.windowList, _window);
  52. }
  53. }
  54. private isLoadding: boolean = false;
  55. /**
  56. * 打开窗口
  57. * @param prefabPath 预制体路径
  58. * @param openMode 窗口打开模式
  59. * @param params 给窗口传递的参数
  60. * @returns
  61. */
  62. public async open(prefabPath: string, openMode: WindowOpenMode, params: any[], onOpening: EventHandler[] = [], onClosing: EventHandler[] = []) {
  63. var _window: Window;
  64. switch (openMode) {
  65. case WindowOpenMode.NotCloseAndAdd:
  66. _window = await this.doOpen(prefabPath, params, onOpening, onClosing);
  67. break;
  68. case WindowOpenMode.NotCloseAndCover:
  69. if (this.currentWindow && prefabPath == this.currentWindow.prefabPath) {
  70. this.currentWindow.setParams(params);
  71. _window = this.currentWindow;
  72. }
  73. else {
  74. _window = await this.doOpen(prefabPath, params, onOpening, onClosing);
  75. }
  76. break;
  77. case WindowOpenMode.CloseAndAdd:
  78. this.close();
  79. _window = await this.doOpen(prefabPath, params, onOpening, onClosing);
  80. break;
  81. case WindowOpenMode.CloseAndCover:
  82. if (this.currentWindow && prefabPath == this.currentWindow.prefabPath) {
  83. this.currentWindow.setParams(params);
  84. _window = this.currentWindow;
  85. }
  86. else {
  87. this.close();
  88. _window = await this.doOpen(prefabPath, params, onOpening, onClosing);
  89. }
  90. break;
  91. default:
  92. break;
  93. }
  94. return _window;
  95. }
  96. private async doOpen(prefabPath: string, params: any[], onOpening: EventHandler[] = [], onClosing: EventHandler[] = []) {
  97. if (this.isLoadding) {
  98. return null;
  99. }
  100. this.isLoadding = true;
  101. var prefab = await ResourcesUtils.load<Prefab>(prefabPath, null, this.node);
  102. var windowNode = instantiate(prefab);
  103. var _window = windowNode.getComponent(Window) || windowNode.addComponent(Window);
  104. _window.node.parent = find(this.canvasName);
  105. _window.setParams(params);
  106. _window.prefabPath = prefabPath;
  107. onClosing && (_window.openWindowOnClosing = onClosing);
  108. for (let i = 0; i < onOpening.length; i++) {
  109. onOpening[i].emit([_window]);
  110. }
  111. this.isLoadding = false;
  112. return _window;
  113. }
  114. public async showTips(message: string, prefabPath: string = "prefabs/ui/tips") {
  115. var _window = await this.open(prefabPath, WindowOpenMode.NotCloseAndAdd, [message]);
  116. if (_window) {
  117. _window.getComponent(Tips) || _window.addComponent(Tips);
  118. }
  119. }
  120. /**
  121. * 关闭窗口
  122. * @param type 指定窗口类型,如果不传则关闭最近打开的窗口
  123. */
  124. public close(type: ui_window | Window | Node = null): void {
  125. if (!this.currentWindow) {
  126. return;
  127. }
  128. if (type) {
  129. var windowList = this.windowList.concat();
  130. for (let i = 0; i < windowList.length; i++) {
  131. const _window = windowList[i];
  132. if (type instanceof Window) {
  133. if (type == _window) {
  134. this.destroyWindow(_window);
  135. }
  136. }
  137. else if (type instanceof Node) {
  138. if (type == _window.node) {
  139. this.destroyWindow(_window);
  140. }
  141. }
  142. else if (_window instanceof type) {
  143. this.destroyWindow(_window);
  144. }
  145. }
  146. }
  147. else {
  148. var _window = this.windowList[this.windowList.length - 1];
  149. this.destroyWindow(_window);
  150. }
  151. }
  152. /**
  153. * 关闭指定路径的窗口
  154. * @param path 路径,例:Canvas/XXWindow
  155. */
  156. public closeByPath(path: string): void {
  157. if (!this.currentWindow) {
  158. return;
  159. }
  160. var _windowNode = find(path);
  161. _windowNode && this.destroyWindow(_windowNode.getComponent(Window));
  162. }
  163. /**
  164. * 关闭所有窗口
  165. */
  166. public closeAll() {
  167. while (this.windowList.length) {
  168. var _window = this.windowList.shift();
  169. this.destroyWindow(_window);
  170. }
  171. }
  172. /**
  173. * 最近打开的窗口
  174. */
  175. public static get currentWindow(): Window {
  176. return this.thisObject.currentWindow;
  177. }
  178. /**
  179. * 打开窗口
  180. * @param prefabPath 预制体路径
  181. * @param openMode 窗口打开模式
  182. * @param params 给窗口传递的参数
  183. * @returns
  184. */
  185. public static async open(prefabPath: string, openMode: WindowOpenMode, params: any[] = [], onOpening: EventHandler[] = [], onClosing: EventHandler[] = []) {
  186. return this.thisObject.open(prefabPath, openMode, params, onOpening, onClosing);
  187. }
  188. /**
  189. * 关闭窗口
  190. * @param type 指定窗口类型,如果不传则关闭最近打开的窗口
  191. */
  192. public static close(type: ui_window | Window | Node = null): void {
  193. this.thisObject.close(type);
  194. }
  195. /**
  196. * 关闭指定路径的窗口
  197. * @param path 路径,例:Canvas/XXWindow
  198. */
  199. public static closeByPath(path: string): void {
  200. this.thisObject.closeByPath(path);
  201. }
  202. /**
  203. * 关闭所有窗口
  204. */
  205. public static closeAll() {
  206. this.thisObject.closeAll();
  207. }
  208. /**
  209. * 显示小提示
  210. * @param message
  211. */
  212. public static showTips(message: string, prefabPath: string = "prefabs/ui/tips") {
  213. this.thisObject.showTips(message, prefabPath);
  214. }
  215. public static getWindowList(): Window[] {
  216. return this.thisObject.windowList.concat();
  217. }
  218. public static onWindowClose(_window: Window) {
  219. this.thisObject.onWindowClose(_window);
  220. }
  221. }
  222. export type ui_window<T = Window> = Constructor<T>;