BaseLayer.ts 13 KB

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