oops-framework框架 之 界面管理(四)

引擎: CocosCreator 3.8.0

环境: Mac

Gitee: oops-game-kit


回顾


在上篇博客中我们讲述下了关于 oops-framework 框架的启动流程和项目启动流程所做的事情相关,详情内容可参考:

oops-framework框架 之 启动流程

oops-framework框架 是由作者dgflash编写,基于CocosCreator3.x而实现的开源框架,为了方便大家更好的学习和使用该框架,作者很贴心准备了各种学习资料:

dgflash-哔哩视频

dgflash CSDN博客

dgflash-cocos论坛

Gitee dgflash项目仓库

注:oops-framework框架QQ群: 628575875

本篇博客主要讲述下框架下的界面管理,以用于构建、显示、隐藏页面相关,以及页面使用的常用接口相关。


界面管理


框架的UI界面主要在场景的gui节点中,该节点被LayerManager模块管理。框架初始化的主要逻辑有:

// ../extensions/oops-plugin-framework/assets/core/Roots.ts
export class Root extends Component {
  @property({type: Node, tooltip: "界面层"})
  gui: Node = null!;
  
  protected init() {
    oops.gui = new LayerManager(this.gui);
    this.initGui();
  }
}

// assets/script/Main.ts
import { UIConfigData } from './game/common/config/GameUIConfig';
export class Main extends Root {
  protected initGui() {
    // 初始化UI界面配置数据进行初始化
    oops.gui.init(UIConfigData);
  }
}

在实际的应用中,对于页面的打开、隐藏我们只要编写:

// 打开新页面
oops.gui.open(UIID.GAME_LOGIN);
// 关闭指定页面
oops.gui.remove(UIID.Loading);

oops.gui的调用入口在 Oop.ts

export class oops {
    static gui: LayerManager;
}

UIID配置信息在GameUIConfig.ts中,该文件主要用于配置UI页面的数据相关

// GameUIConfig.ts
export enum UIID {
    Loading = 1,
    Window,
    Netinstable,
}

export var UIConfigData: { [key: number]: UIConfig } = {
  [UIID.Loading]: { layer: LayerType.UI, prefab: "common/prefab/loading"},
  [UIID.Netinstable]: { layer: LayerType.PopUp, prefab: "common/prefab/netinstable" },
  [UIID.Window]: { layer: LayerType.Dialog, prefab: "common/prefab/window" },
}

// LayerManager.ts
export interface UIConfig {
    bundle?: string;		/** 远程包名 */
    layer: LayerType;		/** 窗口层级 */
    prefab: string;			/** 预制资源相对路径 */
}

简单的理解页面的构建就是:

  1. 构建预制体页面UI
  2. 打开GameUIConfig.ts 文件,配置页面枚举类型,配置页面类型,资源路径
  3. 调用oops.gui.open(UIID)

LayerManager


LayerManager 主要用于管理不同的UI页面,构造函数实现如下:

constructor(root: Node) {
  this.root = root;
  this.camera = this.root.getComponentInChildren(Camera)!;
  // 不同界面类型构建节点,然后顺序添加到根节点中
  this.game = this.create_node(LayerType.Game);
  this.ui = new LayerUI(LayerType.UI);
  this.popup = new LayerPopUp(LayerType.PopUp);
  this.dialog = new LayerDialog(LayerType.Dialog);
  this.system = new LayerDialog(LayerType.System);
  this.notify = new LayerNotify(LayerType.Notify);
  this.guide = this.create_node(LayerType.Guide);
  // 注意下层级, LayerType.Game的最低,LayerType.Guide的最高
  root.addChild(this.game);
  root.addChild(this.ui);
  root.addChild(this.popup);
  root.addChild(this.dialog);
  root.addChild(this.system);
  root.addChild(this.notify);
  root.addChild(this.guide);
}

private create_node(name: string) {
  var node = new Node(name);
  node.layer = Layers.Enum.UI_2D;
  // 添加widget组件,设置上下左右对齐和对齐模式
  var w: Widget = node.addComponent(Widget);
  w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true;
  w.left = w.right = w.top = w.bottom = 0;
  w.alignMode = 2;
  w.enabled = true;
  return node;
}

主要页面的类型有:

类型说明
Game游戏层,比如地图逻辑处理
UI主界面层,比如地图上方的菜单页面
PopUp弹窗层, 窗口显示后,支持非窗口区域点击,可显示多个不同配置的弹窗
Dialog模式窗口层,窗口显示后,非窗口区域不可透点
System系统窗口层,与Dialog类似,可用于显示系统信息的弹窗错误提示
Notify提示信息层, Tip信息显示,显示以后会上移消失
Guide新手引导层,用于新手的强制引导

页面的继承结构:

主界面
游戏层
引导层
PopUp弹窗
Toast消息
Dialog窗口/System窗口
LayerUI
Node
Game
Guide
LayerPopUp
LayerNotify
LayerDialog

常用的参数或接口:

参数或接口说明
root获取界面根节点
camera获取界面摄像机
game获取游戏界面根节点
guide获取新手引导
uiMap获取界面地图
setUIMap()界面地图配置数据
toast()Tip提示显示,支持是否显示多语言
open()根据uiId,同步打开某个页面
openAsync()根据uiId,异步打开某个页面
has()根据uiId, 检测是否存在某个页面
remove()根据uiId,移除某个页面或窗口
removeByNode()根据this框架添加的节点,移除某个页面或窗口
clear()清除所有窗口

通过 oops.gui.open 打开某个窗口,看下框架的逻辑实现:

/*
@func: 同步打开一个窗口
@param: uiId 窗口唯一标识符ID
@param: uiArgs 页面参数,可以通过回调对象的onAdded或onRemoved回调获取
@param: callbacks 回调对象
*/
open(uiId: number, uiArgs: any = null, callbacks?: UICallbacks): void {
  var config = this.configs[uiId];
  if (config == null) {
    warn(`打开编号为【${uiId}】的界面失败,配置信息不存在`);
    return;
  }

	// 根据不同的界面类型打开不同窗口的显示逻辑
  switch (config.layer) {
    case LayerType.UI:
      this.ui.add(config, uiArgs, callbacks);
      break;
    case LayerType.PopUp:
      this.popup.add(config, uiArgs, callbacks);
      break;
    case LayerType.Dialog:
      this.dialog.add(config, uiArgs, callbacks);
      break;
    case LayerType.System:
      this.system.add(config, uiArgs, callbacks);
      break;
  }
}

页面的打开是支持页面参数传递的,新页面可以通过 UICallbacks 的回调调用

// ../oops-plugin-framework/assets/core/gui/layer/Defines.ts
export interface UICallbacks {
  // 节点添加到层级以后的回调,参数为当前页面节点,传递参数
  onAdded?: (node: Node, params: any) => void,
  // 窗口节点destroy之后回调,参数为当前页面节点,传递参数
  onRemoved?: (node: Node | null, params: any) => void,
  // 页面在移除的时候,进行的调用,可用于隐藏动画的显示,参数为当前页面节点,回调
  // 注意:如果调用`this.node.destroy()`,该回调将直接忽略
  onBeforeRemove?: (node: Node, next: Function) => void
}

注:新页面的打开传递参数可调用onAdded方法


常用示例


打开关闭页面

oops.gui.open(UIID.UI_MAIN);

// 关闭方式1: 通过UIID移除窗口,默认释放
oops.gui.remove(UIID.Loading);

// 方式2: 通过this.node释放窗口,默认保留对象
oops.gui.open(UIID.UI_MAIN);
oops.gui.removeByNode(this.node, true);

打开新页面传递参数

let params = {
  data: "oops"
}
oops.gui.open(UIID.MAIN, param);

// MainLayer.ts
export class MainLayer extends Component {
  onAdded(params?: any) {
    if (!params) {
      return;
    }
    let data = params.data;
    // todo
  }
}

弹窗页面显示

弹窗的类型虽有PopUp,Dialog,System的几种类型,但他们是类似的:

  • PopUp 打开以后,支持非窗口区域透点,支持打开多个不同配置的弹窗
  • Dialog 仅支持显示一个,非窗口区域不可透点
  • SystemDialog类似,作者dgflash增加这个处理的原因主要是为了区别窗口提示的不同类型,比如客户端自身和服务器的提示,方便问题的定位。

增加一个窗口的UI预制体,如下图所示:
请添加图片描述

GameUIConfig.ts中增加配置后, 添加示例:

public openWindow(event, customData: string) {
  let params = {
    title: "窗口标题",
    content: "这是一段描述",
  }
  let callBack: UICallbacks = {
    onAdded: (node: Node, params: any) => {
      console.log("onAdded获取传递的参数:", params)
    },
    onRemoved:(node: Node | null, params: any) => {
      console.log("onRemoved获取传递的参数:", params)     
    }
  }
  oops.gui.open(UIID.UI_POPUP, params, callBack);
}

一般弹窗的出现是需要有显示或隐藏动画的,我们可以通过回调方法:

  • onAdded 增加显示动画
  • onBeforeRemove 增加隐藏动画

动画的显示可以通过tween缓动系统或CocosCreator的Animation组件进行添加:

public clickSystem(event, customData: string) {
    console.log(customData);
    let params = {
      title: `系统窗口`,
      content: "数据异常",
    }
    oops.gui.open(UIID.UI_SYSTEM, params, this.getPopCommonEffect());
}

// 弹窗动画
private getPopCommonEffect(callbacks?: PopViewParams) {
	let newCallbacks: PopViewParams = {
		// 节点添加动画
    onAdded: (node, params) => {
      node.setScale(0.1, 0.1, 0.1);
      tween(node)
        .to(0.2, { scale: new Vec3(1, 1, 1) })
        .start();
    },
    // 节点删除动画
    onBeforeRemove: (node, next) => {
      tween(node)
        .to(0.2, { scale: new Vec3(0.1, 0.1, 0.1) })
        .call(next)
        .start();
    },
	}

	if (callbacks) {
    if (callbacks && callbacks.onAdded) {
      let onAdded = callbacks.onAdded;
      callbacks.onAdded = (node: Node, params: any) => {
        onAdded(node, params);
        newCallbacks.onAdded(node, params);
      };
    }

    if (callbacks && callbacks.onBeforeRemove) {
      let onBeforeRemove = callbacks.onBeforeRemove;
      callbacks.onBeforeRemove = (node, params) => {
        onBeforeRemove(node, params);
        newCallbacks.onBeforeRemove(node, params);
      };
    }
    return callbacks;
  }
  return newCallbacks;
}

注:作者在oops-frameworkTipsManager.ts中增加了更多的窗口示例,推荐查看学习

Toast示例

提示内容的显示就相对简单了,主要代码如下:

private _tipIndex: number = 0;

public clickTip(event, customData: string) {
  this._tipIndex++;
  // 参数:内容,是否使用多语言默认false
  oops.gui.toast(`这是第${this._tipIndex}个提示`);
}

最后,祝大家学习和生活愉快!

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹤九日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值