BaseLayer.ts 13 KB

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