BaseLayer.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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, "ui_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. anim.play(name);
  170. return;
  171. }
  172. console.error("ui:" + id + "缺少Animation组件");
  173. } else {
  174. callback && callback();
  175. callback = null;
  176. }
  177. }
  178. private _updateUI() {
  179. if (this._layer_manage) {
  180. let show_idx = this._layer_cache.length - 1, hide_idx = 0;;
  181. for (; show_idx >= 0; --show_idx) {
  182. if (this._layer_cache[show_idx].active) {
  183. this._layer_cache[show_idx].view?.onShow();
  184. let mode = this._layer_cache[show_idx].view?.show_type;
  185. if (mode == UIShowType.Single) {
  186. for (let i = 0; i < this._bottom_layer; ++i) {
  187. this._layer_cache[i] && this._layer_cache[i].view?.onShow();
  188. }
  189. hide_idx = this._bottom_layer;
  190. break;
  191. } else if (mode == UIShowType.FullScreen) {
  192. break;
  193. }
  194. }
  195. }
  196. for (let i = hide_idx; i < show_idx; ++i) {
  197. this._layer_cache[i].view?.onHide();
  198. }
  199. let find = false;
  200. for (let cache of this._layer_cache) {
  201. if (cache.active) {
  202. if (cache.view?.show_type == UIShowType.FullScreen) {
  203. find = true;
  204. //如果有全屏隐藏底层UI
  205. for (let i = 0; i < this._bottom_layer; ++i) {
  206. this._layer_cache[i] && this._layer_cache[i].view?.onHide();
  207. }
  208. break;
  209. }
  210. }
  211. }
  212. EventMgr.fireEvent("_Framewrok_Show_GameLayer", !find);
  213. }
  214. }
  215. /**
  216. * 关闭UI
  217. * @param ui 该值可为UIID也可为this
  218. */
  219. close(ui: number | BaseView) {
  220. let view = (typeof ui === "number") ? this.getUIView(ui) : ui;
  221. if (view) {
  222. let info: LayerInfo = null;
  223. for (let i = 0; i < this._layer_cache.length; ++i) {
  224. info = this._layer_cache[i];
  225. if (info.view == view) {
  226. this._layer_cache.splice(i, 1);
  227. //刷新UI
  228. let pre_info = (this._layer_cache.length >= 1) ? this._layer_cache[this._layer_cache.length - 1] : null;
  229. if (pre_info) {
  230. if (!pre_info.active) {
  231. pre_info = (this._layer_cache.length >= 2) ? this._layer_cache[this._layer_cache.length - 2] : null;
  232. }
  233. }
  234. this._updateUI();
  235. this._play_anim(info.view.view_id, info.view.node, "ui_close", () => {
  236. //显示最后一个UI
  237. if (pre_info && pre_info.view) {
  238. pre_info.view.onShow();
  239. }
  240. this._clearUI(info);
  241. });
  242. break;
  243. }
  244. }
  245. }
  246. else{
  247. let info: LayerInfo = null;
  248. for (let i = 0; i < this._layer_cache.length; ++i) {
  249. info = this._layer_cache[i];
  250. if(info.id == ui){
  251. info.bLoading = false;
  252. console.log("closeUI with out view:", info.id);
  253. }
  254. }
  255. }
  256. }
  257. ShowUI(UI, state, callback: Function = null, args: any[]) {
  258. let nohave = true;
  259. let exist = []
  260. for (let i in this._layer_cache) {
  261. if (this._layer_cache[i].id === UI) {
  262. nohave = false
  263. if (this._layer_cache[i] && this._layer_cache[i].view) {
  264. if (state) {
  265. for (let existUI of exist) {
  266. existUI.view.onHide();
  267. }
  268. this._layer_cache[i].view.onShow();
  269. this._layer_cache[i].active = true;
  270. } else {
  271. for (let existUI of exist) {
  272. existUI.view.onShow();
  273. }
  274. this._layer_cache[i].view.onHide();
  275. this._layer_cache[i].active = false;
  276. }
  277. callback && callback();
  278. }
  279. return;
  280. }
  281. exist.push(this._layer_cache[i])
  282. }
  283. if (nohave) {
  284. this.open(UI, callback, args);
  285. }
  286. }
  287. /**
  288. * 获取UI对应的UIView
  289. * @param id UIID
  290. */
  291. getUIView(id: number) {
  292. for (let ui of this._layer_cache) {
  293. if (ui.id === id) {
  294. if (ui.active) {
  295. return ui.view;
  296. }
  297. }
  298. }
  299. return null;
  300. }
  301. /**
  302. * 关闭当前层的所有UI
  303. */
  304. closeAll(withoutID: number = -1) {
  305. for (let index = this._layer_cache.length - 1; index >= 0; index--) {
  306. let info = this._layer_cache[index];
  307. if (info.id !== withoutID) {
  308. this.close(info.id);
  309. let conf = this._layer_conf[info.id];
  310. (!conf.special) && this._clearUI(info);
  311. }
  312. }
  313. this._layer_queue = [];
  314. }
  315. private _clearUI(info: LayerInfo) {
  316. if (info && info.view) {
  317. let conf = this._layer_conf[info.id];
  318. (conf && conf.bottom) && --this._bottom_layer;
  319. info.view.onClose();
  320. //发送打开事件
  321. EventMgr.fireEvent(FrameworkConf.Event.CLOSE_UI, info.id);
  322. info.view.unscheduleAllCallbacks();
  323. info.view.node.removeFromParent();
  324. info.view.release();
  325. EventMgr.removeEvent(info.view);
  326. info.view.node.destroyAllChildren();
  327. info.view.node.destroy();
  328. info.res && (info.res.decRef());
  329. info.res = null;
  330. info.view = null;
  331. info = null;
  332. }
  333. }
  334. showLayerUI(show: boolean) {
  335. for (let cache of this._layer_cache) {
  336. if (show) {
  337. cache.active && cache.view?.onShow();
  338. } else {
  339. cache.view?.onHide();
  340. }
  341. }
  342. }
  343. }