BaseLayer.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import { Animation, Canvas, find, instantiate, Node, Prefab, Sprite, Widget } from 'cc';
  2. import { PREVIEW } from 'cc/env';
  3. import { FrameworkConf } from '../config/FrameworkConf';
  4. import { EventMgr } from '../event/EventManager';
  5. import { resLoader } from '../res/ResLoader';
  6. import { StringUtil } from '../util/StringUtil';
  7. import { TimeUtil } from '../util/TimeUtil';
  8. import { BaseView, UIShowType } from './BaseView';
  9. import { LayerConf, LayerInfo } from './LayerManager';
  10. import { UserData } from '../../game/data/UserData';
  11. import { Layer_Conf, ViewID } from '../config/LayerConf';
  12. export class BaseLayer extends Node {
  13. private _layer_queue: LayerInfo[] = []; //UI队列
  14. private _layer_conf: { [key: number]: LayerConf } = {}; //UI配置
  15. private _layer_opening: boolean = false; //是否正在打开UI
  16. private _layer_cache: LayerInfo[] = []; //UI缓存
  17. private _layer_manage = false; //是否启用层级管理
  18. private _bottom_layer = 0; //底层UI数量(通常位于UI栈底部,不受UI切换影响)
  19. constructor(name: string, conf: any, manage: boolean = false) {
  20. super(name);
  21. this._layer_conf = conf;
  22. let widget = this.addComponent(Widget);
  23. widget.isAlignLeft = widget.isAlignRight = widget.isAlignTop = widget.isAlignBottom = true;
  24. widget.left = widget.right = widget.top = widget.bottom = 0;
  25. widget.alignMode = 2;
  26. widget.enabled = true;
  27. this._layer_queue = [];
  28. this._layer_cache = [];
  29. this._layer_opening = false;
  30. this._layer_manage = manage;
  31. }
  32. /**
  33. * 打开UI
  34. * @param id UIID
  35. * @param args 打开UI的可传参数
  36. * @param callback UI打开成功过后的回调
  37. */
  38. open(id: number, callback: Function = null, args: any[]) {
  39. let conf = this._layer_conf[id];
  40. if (conf) {
  41. let info: LayerInfo = {
  42. id: id,
  43. args: args,
  44. view: null,
  45. res: null,
  46. callback: callback,
  47. active: true,
  48. bLoading: true
  49. };
  50. if (this._layer_opening) {
  51. //队列里不能有相同的UI
  52. for (let ui of this._layer_queue) {
  53. if (ui.id === id) {
  54. return false;
  55. }
  56. }
  57. //插入待打开队列
  58. this._layer_queue.push(info);
  59. return false;
  60. }
  61. //开同一UI 则刷新
  62. let curView = this.getUIView(id);
  63. if (curView) {
  64. //let conf = this._layer_conf[id];
  65. if (conf.reset) {
  66. console.log("页面存在,直接刷新")
  67. //传递自定义参数
  68. curView.onOpen(...info.args);
  69. //回调
  70. info.callback && info.callback();
  71. return true
  72. }
  73. else {
  74. console.log("页面存在,不刷新")
  75. return false;
  76. }
  77. }
  78. this._layer_opening = true;
  79. this._layer_cache.push(info);
  80. let __time = TimeUtil.getTime();
  81. let self = this
  82. /**
  83. * 加载失败
  84. * @param bRes 资源已加载
  85. */
  86. let funError = function (bRes) {
  87. if (bRes) {
  88. resLoader.release(conf.url, conf.bundle);
  89. }
  90. for (let i = self._layer_cache.length - 1; i >= 0; --i) {
  91. if (self._layer_cache[i] == info) {
  92. self._layer_cache.splice(i, 1);
  93. break;
  94. }
  95. }
  96. //处理待打开队列中的UI
  97. self._layer_opening = false;
  98. self._open_next();
  99. }
  100. //加载资源
  101. resLoader.load(conf.bundle, conf.url, Prefab, (error: Error, prefab: Prefab) => {
  102. if (error) {
  103. console.error("载入资源失败:" + conf.url);
  104. funError(false)
  105. return false
  106. } else {
  107. if (!info.bLoading) {
  108. console.error("资源已不需要了:" + conf.url);
  109. funError(true)
  110. return false
  111. }
  112. info.bLoading = false;
  113. (!conf.cache) && (info.res = prefab);
  114. let node = instantiate(prefab);
  115. node.active = true;
  116. console.log(`复制预制体:${conf.url}`)
  117. if (!node) {
  118. console.error("初始化Node失败");
  119. funError(true)
  120. return false;
  121. }
  122. let view = node.getComponent(BaseView);
  123. if (!view) {
  124. console.error("UI未找到UIView组件");
  125. funError(true)
  126. return false;
  127. }
  128. prefab.addRef();
  129. view.enabled = true;
  130. info.view = view;
  131. view.view_id = id;
  132. this.addChild(node);
  133. //统计底层UI数量
  134. (conf.bottom) && ++this._bottom_layer;
  135. this._play_anim(id, node, "open", () => {
  136. //刷新UI
  137. this._updateUI();
  138. //传递自定义参数
  139. view.onOpen(...info.args);
  140. //发送打开事件
  141. EventMgr.fireEvent(FrameworkConf.Event.OPEND_UI, info.id);
  142. //回调
  143. info.callback && info.callback();
  144. //处理待打开队列中的UI
  145. this._layer_opening = false;
  146. this._open_next();
  147. });
  148. (PREVIEW) && console.log(StringUtil.format("UI[{0}]加载耗时:{1}毫秒", ViewID[info.id], TimeUtil.getTime() - __time));
  149. }
  150. });
  151. return true;
  152. }
  153. return false;
  154. }
  155. private _open_next() {
  156. let info = this._layer_queue.shift();
  157. info && this.open(info.id, info.callback, info.args);
  158. }
  159. private _play_anim(id: number, node: Node, name: string, callback: Function,) {
  160. //是否播放动画
  161. let conf = this._layer_conf[id];
  162. if (conf.anim) {
  163. let anim = node.getComponent(Animation);
  164. if (anim) {
  165. anim.on(Animation.EventType.FINISHED, () => {
  166. callback && callback();
  167. callback = null;
  168. }, this);
  169. let animName = "";
  170. if (conf.anim == 1) {
  171. animName = "ui_" + name;
  172. } else if (conf.anim == 2) {
  173. animName = "tips_" + name;
  174. }
  175. anim.play(animName);
  176. return;
  177. }
  178. console.error("ui:" + id + "缺少Animation组件");
  179. } else {
  180. callback && callback();
  181. callback = null;
  182. }
  183. }
  184. private _updateUI() {
  185. if (this._layer_manage) {
  186. let show_idx = this._layer_cache.length - 1, hide_idx = 0;;
  187. for (; show_idx >= 0; --show_idx) {
  188. if (this._layer_cache[show_idx].active) {
  189. this._layer_cache[show_idx].view?.onShow();
  190. let mode = this._layer_cache[show_idx].view?.show_type;
  191. if (mode == UIShowType.Single) {
  192. for (let i = 0; i < this._bottom_layer; ++i) {
  193. this._layer_cache[i] && this._layer_cache[i].view?.onShow();
  194. }
  195. hide_idx = this._bottom_layer;
  196. break;
  197. } else if (mode == UIShowType.FullScreen) {
  198. break;
  199. }
  200. }
  201. }
  202. for (let i = hide_idx; i < show_idx; ++i) {
  203. this._layer_cache[i].view?.onHide();
  204. }
  205. let find = false;
  206. for (let cache of this._layer_cache) {
  207. if (cache.active) {
  208. if (cache.view?.show_type == UIShowType.FullScreen) {
  209. find = true;
  210. //如果有全屏隐藏底层UI
  211. for (let i = 0; i < this._bottom_layer; ++i) {
  212. this._layer_cache[i] && this._layer_cache[i].view?.onHide();
  213. }
  214. break;
  215. }
  216. }
  217. }
  218. EventMgr.fireEvent("_Framewrok_Show_GameLayer", !find);
  219. }
  220. }
  221. /**
  222. * 关闭UI
  223. * @param ui 该值可为UIID也可为this
  224. */
  225. close(ui: number | BaseView) {
  226. let view = (typeof ui === "number") ? this.getUIView(ui) : ui;
  227. if (view) {
  228. let info: LayerInfo = null;
  229. for (let i = 0; i < this._layer_cache.length; ++i) {
  230. info = this._layer_cache[i];
  231. if (info.view == view) {
  232. this._layer_cache.splice(i, 1);
  233. //刷新UI
  234. let pre_info = (this._layer_cache.length >= 1) ? this._layer_cache[this._layer_cache.length - 1] : null;
  235. if (pre_info) {
  236. if (!pre_info.active) {
  237. pre_info = (this._layer_cache.length >= 2) ? this._layer_cache[this._layer_cache.length - 2] : null;
  238. }
  239. }
  240. this._updateUI();
  241. this._play_anim(info.view.view_id, info.view.node, "close", () => {
  242. //显示最后一个UI
  243. if (pre_info && pre_info.view) {
  244. pre_info.view.onShow();
  245. }
  246. this._clearUI(info);
  247. });
  248. break;
  249. }
  250. }
  251. }
  252. else {
  253. let info: LayerInfo = null;
  254. for (let i = 0; i < this._layer_cache.length; ++i) {
  255. info = this._layer_cache[i];
  256. if (info.id == ui) {
  257. info.bLoading = false;
  258. console.log("closeUI with out view:", info.id);
  259. }
  260. }
  261. }
  262. }
  263. ShowUI(UI, state, callback: Function = null, args: any[]) {
  264. let nohave = true;
  265. let exist = []
  266. for (let i in this._layer_cache) {
  267. if (this._layer_cache[i].id === UI) {
  268. nohave = false
  269. if (this._layer_cache[i] && this._layer_cache[i].view) {
  270. if (state) {
  271. for (let existUI of exist) {
  272. existUI.view.onHide();
  273. }
  274. this._layer_cache[i].view.onShow();
  275. this._layer_cache[i].active = true;
  276. } else {
  277. for (let existUI of exist) {
  278. existUI.view.onShow();
  279. }
  280. this._layer_cache[i].view.onHide();
  281. this._layer_cache[i].active = false;
  282. }
  283. callback && callback();
  284. }
  285. return;
  286. }
  287. exist.push(this._layer_cache[i])
  288. }
  289. if (nohave) {
  290. this.open(UI, callback, args);
  291. }
  292. }
  293. /**
  294. * 获取UI对应的UIView
  295. * @param id UIID
  296. */
  297. getUIView(id: number) {
  298. for (let ui of this._layer_cache) {
  299. if (ui.id === id) {
  300. if (ui.active) {
  301. return ui.view;
  302. }
  303. }
  304. }
  305. return null;
  306. }
  307. /**
  308. * 关闭当前层的所有UI
  309. */
  310. closeAll(withoutID: number = -1) {
  311. for (let index = this._layer_cache.length - 1; index >= 0; index--) {
  312. let info = this._layer_cache[index];
  313. if (info.id !== withoutID) {
  314. this.close(info.id);
  315. let conf = this._layer_conf[info.id];
  316. (!conf.special) && this._clearUI(info);
  317. }
  318. }
  319. this._layer_queue = [];
  320. }
  321. private _clearUI(info: LayerInfo) {
  322. if (info && info.view) {
  323. let conf = this._layer_conf[info.id];
  324. (conf && conf.bottom) && --this._bottom_layer;
  325. info.view.onClose();
  326. //发送打开事件
  327. EventMgr.fireEvent(FrameworkConf.Event.CLOSE_UI, info.id);
  328. info.view.unscheduleAllCallbacks();
  329. info.view.node.removeFromParent();
  330. info.view.release();
  331. EventMgr.removeEvent(info.view);
  332. info.view.node.destroyAllChildren();
  333. info.view.node.destroy();
  334. info.res && (info.res.decRef());
  335. info.res = null;
  336. info.view = null;
  337. info = null;
  338. }
  339. }
  340. showLayerUI(show: boolean) {
  341. for (let cache of this._layer_cache) {
  342. if (show) {
  343. cache.active && cache.view?.onShow();
  344. } else {
  345. cache.view?.onHide();
  346. }
  347. }
  348. }
  349. }