调整布局、新增导航栏,调整页面跳转逻辑

This commit is contained in:
2025-09-12 18:20:41 +08:00
parent c11a310ea1
commit 0e86ba3454
23 changed files with 4677 additions and 618 deletions
@@ -1,6 +1,10 @@
import { ViewManager } from "db://assets/Scripts/Main/Manager/ViewManager";
import { UITransitionHelper } from "../utils/UITransitionHelper";
import GameRootUI from "../../Main/Common/GameRootUI";
import { Node } from "cc";
import li_EventManager from "../../Main/Common/li_EventManager";
import { InnerMsgCode } from "../../Main/Config/InnerMsgCode";
import { ThemePanel } from "../ui/panels/ThemePanel";
/**
* 页面过渡动画类型枚举
@@ -11,6 +15,16 @@ export enum PageTransitionType {
SLIDE_RIGHT = "slide_right",
}
/**
* NavigationPanel面板类型枚举
*/
export enum PanelType {
THEME = "ThemePanel",
GIRL_DETAIL = "GirlDetailPanel",
CHAT = "ChatPanel",
SETTING = "SettingPanel",
}
/**
* 页面过渡动画配置接口
*/
@@ -25,6 +39,7 @@ export interface PageTransitionConfig {
* 导航管理器
*
* 负责管理游戏中的页面导航和路由,将导航逻辑从业务逻辑中分离出来
* 统一管理NavigationPanel和其他面板的切换
*
* @author AI Chat System
* @version 1.0.0
@@ -32,6 +47,16 @@ export interface PageTransitionConfig {
export class NavigationManager {
private static _instance: NavigationManager;
// NavigationPanel相关属性
private navigationPanel: any = null; // NavigationPanel实例引用
private currentActivePanel: PanelType = PanelType.THEME;
private panelCache: Map<PanelType, Node> = new Map(); // 面板缓存
private currentVisiblePanel: Node = null;
// 选中的角色相关信息
private selectedGirlId: number = 1; // 当前选中的角色ID
private selectedThemeId: number = 1; // 当前选中的主题ID
/**
* 获取NavigationManager的单例实例
*
@@ -45,7 +70,350 @@ export class NavigationManager {
return this._instance;
}
private constructor() {}
private constructor() {
// 初始化事件监听
this.initEventListeners();
}
/**
* 初始化事件监听
*/
private initEventListeners(): void {
// 监听导航面板切换事件
li_EventManager.I.addInnerEL(
InnerMsgCode.Navigation_PanelSwitch,
this.onNavigationEvent,
this
);
}
/**
* 处理导航事件
*/
private onNavigationEvent(panelType: PanelType): void {
console.log(
"[NavigationManager] Received navigation event for:",
panelType
);
this.switchToPanel(panelType);
}
/**
* 注册NavigationPanel实例
* @param panel NavigationPanel实例
*/
public registerNavigationPanel(panel: any): void {
this.navigationPanel = panel;
console.log("[NavigationManager] NavigationPanel registered");
}
/**
* 统一的面板切换方法
* @param panelType 目标面板类型
*/
public switchToPanel(panelType: PanelType, force: boolean = false): void {
if (this.currentActivePanel === panelType && !force) {
return;
}
if (!this.navigationPanel) {
console.warn(
"[NavigationManager] NavigationPanel not registered, fallback to direct ViewManager call"
);
this.fallbackSwitchPanel(panelType);
return;
}
// 通知NavigationPanel显示加载状态
this.navigationPanel.showLoading?.();
// 计算动画方向
const currentIndex = this.getPanelIndex(this.currentActivePanel);
const targetIndex = this.getPanelIndex(panelType);
const isMovingRight = currentIndex < targetIndex;
const hideDirection = isMovingRight ? "left" : "right";
const showDirection = isMovingRight ? "right" : "left";
// 隐藏当前面板(包括子页面)
this.hideCurrentPanelWithChildren(hideDirection);
// 加载并显示目标面板
this.loadOrGetPanel(panelType, (panel: Node) => {
this.currentActivePanel = panelType;
this.currentVisiblePanel = panel;
// 更新NavigationPanel按钮状态
this.navigationPanel.updateButtonStates?.(panelType);
// 显示面板
this.showPanelWithAnimation(panel, showDirection, () => {
this.navigationPanel.hideLoading?.();
});
});
}
/**
* 获取面板索引(用于动画方向计算)
*/
private getPanelIndex(panelType: PanelType): number {
switch (panelType) {
case PanelType.THEME:
return 0;
case PanelType.GIRL_DETAIL:
return 1;
case PanelType.CHAT:
return 2;
case PanelType.SETTING:
return 3;
default:
return 0;
}
}
/**
* 获取面板名称
*/
private getPanelName(panelType: PanelType): string {
return panelType as string;
}
/**
* 获取面板数据
*/
private getPanelData(panelType: PanelType): any {
switch (panelType) {
case PanelType.GIRL_DETAIL:
return this.selectedGirlId; // 使用当前选中的角色ID
case PanelType.CHAT:
return { girlId: this.selectedGirlId }; // 使用当前选中的角色ID
default:
return null;
}
}
/**
* 加载或获取面板
*/
private loadOrGetPanel(
panelType: PanelType,
callback: (panel: Node) => void
) {
// 检查缓存
if (this.panelCache.has(panelType)) {
const cachedPanel = this.panelCache.get(panelType);
if (cachedPanel && cachedPanel.isValid) {
// 特殊处理:主题面板刷新(避免重复调用Show)
if (panelType === PanelType.THEME) {
const themePanel = cachedPanel.getComponent(ThemePanel);
if (themePanel) {
// 不在这里调用Show(),因为ThemePanel已经有加载状态保护
// 只在必要时调用onHide()确保子页面状态正确
if (typeof themePanel.onHide === "function") {
console.log("[NavigationManager] 确保主题面板子页面状态正确");
themePanel.onHide();
}
}
}
callback(cachedPanel);
return;
} else {
this.panelCache.delete(panelType);
}
}
// 加载新面板
const panelName = this.getPanelName(panelType);
const openData = this.getPanelData(panelType);
ViewManager.I.openBundlesView(panelName, openData, (panel: Node) => {
if (panel && panel.isValid) {
this.panelCache.set(panelType, panel);
callback(panel);
}
});
}
/**
* 隐藏当前面板及其子页面
*/
private hideCurrentPanelWithChildren(direction: "left" | "right") {
if (!this.currentVisiblePanel) {
return;
}
// 如果当前是ThemePanel,需要同时处理可能的子页面(GirlListPanel
if (this.currentActivePanel === PanelType.THEME) {
// 查找并隐藏GirlListPanel子页面
this.hideThemePanelChildren(direction);
// 隐藏ThemePanel主面板
this.hidePanelWithAnimation(this.currentVisiblePanel, direction);
} else {
// 其他面板直接隐藏
this.hidePanelWithAnimation(this.currentVisiblePanel, direction);
}
}
/**
* 隐藏ThemePanel的子页面
*/
private hideThemePanelChildren(direction: "left" | "right") {
const themePanelNode = this.findThemePanelNode();
if (themePanelNode) {
const themePanelComponent = themePanelNode.getComponent("ThemePanel");
if (themePanelComponent) {
// 获取子页面节点
const childPanel = this.getThemePanelChildNode(themePanelComponent);
if (childPanel && childPanel.active) {
console.log(
"[NavigationManager] Hiding ThemePanel child with animation"
);
this.hidePanelWithAnimation(childPanel, direction);
}
}
}
}
/**
* 获取ThemePanel的子页面节点
*/
private getThemePanelChildNode(themePanelComponent: any): Node | null {
try {
// ThemePanel存储子页面在currentChildPanel属性中
if (
themePanelComponent.currentChildPanel &&
themePanelComponent.currentChildPanel.node
) {
return themePanelComponent.currentChildPanel.node;
}
// 如果没有直接的引用,尝试通过ViewManager查找GirlListPanel
const viewList = (ViewManager.I as any).m_viewList;
if (viewList) {
for (let i = 0; i < viewList.length; i++) {
const view = viewList[i];
if (
view &&
view.isValid &&
view.name === "GirlListPanel" &&
view.active
) {
return view;
}
}
}
return null;
} catch (error) {
console.error(
"[NavigationManager] Error getting child panel node:",
error
);
return null;
}
}
/**
* 隐藏面板动画
*/
private hidePanelWithAnimation(
panel: Node,
direction: "left" | "right",
callback?: Function
) {
if (!panel || !panel.isValid || !panel.active) {
callback && callback();
return;
}
if (direction === "left") {
UITransitionHelper.slideOutToLeft(panel, 0.3, () => {
panel.active = false;
callback && callback();
});
} else {
UITransitionHelper.slideOutToRight(panel, 0.3, () => {
panel.active = false;
callback && callback();
});
}
}
/**
* 显示面板动画
*/
private showPanelWithAnimation(
panel: Node,
direction: "left" | "right",
callback?: Function
) {
if (!panel || !panel.isValid) {
callback && callback();
return;
}
panel.active = true;
if (direction === "right") {
UITransitionHelper.slideInFromRight(panel, 0.3, () => {
callback && callback();
});
} else {
UITransitionHelper.slideInFromLeft(panel, 0.3, () => {
callback && callback();
});
}
}
/**
* 后备切换方法(当NavigationPanel未注册时)
*/
private fallbackSwitchPanel(panelType: PanelType): void {
const panelName = this.getPanelName(panelType);
const openData = this.getPanelData(panelType);
ViewManager.I.openBundlesView(panelName, openData);
}
/**
* 获取当前激活的面板类型
*/
public getCurrentActivePanel(): PanelType {
return this.currentActivePanel;
}
/**
* 设置选中的角色ID
* @param girlId 角色ID
*/
public setSelectedGirlId(girlId: number): void {
this.selectedGirlId = girlId;
console.log("[NavigationManager] Selected girl ID set to:", girlId);
}
/**
* 获取当前选中的角色ID
* @returns 当前选中的角色ID
*/
public getSelectedGirlId(): number {
return this.selectedGirlId;
}
/**
* 设置选中的主题ID
* @param themeId 主题ID
*/
public setSelectedThemeId(themeId: number): void {
this.selectedThemeId = themeId;
console.log("[NavigationManager] Selected theme ID set to:", themeId);
}
/**
* 获取当前选中的主题ID
* @returns 当前选中的主题ID
*/
public getSelectedThemeId(): number {
return this.selectedThemeId;
}
/**
* 通用页面导航方法,支持过渡动画
@@ -89,6 +457,11 @@ export class NavigationManager {
transitionConfig.outgoingTransition !== PageTransitionType.NONE;
if (!useTransition) {
// 在没有过渡动画的情况下,也需要处理子页面逻辑
if (targetPanel && targetPanel !== "GirlListPanel") {
this.handleThemePanelChildPanelsOnNavigation();
}
ViewManager.I.openBundlesView(targetPanel, navigationData, onComplete);
if (
currentPanel &&
@@ -129,6 +502,7 @@ export class NavigationManager {
duration: number,
onComplete?: Function
): void {
const targetPanelName = targetNode ? targetNode.name : null;
const executeIncomingAnimation = (callback?: Function) => {
if (
config.incomingTransition === PageTransitionType.NONE ||
@@ -191,8 +565,27 @@ export class NavigationManager {
currentPanel.onClose &&
typeof currentPanel.onClose === "function"
) {
if (currentPanel.node.name !== "ThemePanel") currentPanel.onClose();
if (currentPanel.node.name !== "ThemePanel") {
currentPanel.onClose();
} else {
// 如果当前面板是 ThemePanel,检查是否需要关闭子页面
console.log(
"[NavigationManager] ThemePanel detected, checking for child panels"
);
if (
currentPanel.closeChildPanel &&
typeof currentPanel.closeChildPanel === "function"
) {
currentPanel.closeChildPanel();
}
}
}
// 检查目标面板是否会导致需要隐藏 ThemePanel 的子页面
if (targetPanelName && targetPanelName !== "GirlListPanel") {
this.handleThemePanelChildPanelsOnNavigation();
}
onComplete && onComplete();
};
@@ -215,7 +608,7 @@ export class NavigationManager {
}
/**
* 进入角色列表页面
* 进入角色列表页面(作为 ThemePanel 的子页面)
*
* @param {number} themeId - 主题ID,用于筛选角色
*
@@ -224,55 +617,180 @@ export class NavigationManager {
* NavigationManager.Instance.navigateToGirlList(1);
* ```
*/
public navigateToGirlList(themeId: number): void;
/**
* 进入角色列表页面(带过渡动画)
*
* @param {number} themeId - 主题ID,用于筛选角色
* @param {PageTransitionConfig} transitionConfig - 过渡动画配置
* @param {any} currentPanel - 当前面板实例(可选)
*
* @example
* ```typescript
* NavigationManager.Instance.navigateToGirlList(1,
* { incomingTransition: PageTransitionType.SLIDE_RIGHT, outgoingTransition: PageTransitionType.FADE },
* this
* );
* ```
*/
public navigateToGirlList(
themeId: number,
transitionConfig?: PageTransitionConfig,
currentPanel?: any
): void;
public navigateToGirlList(
themeId: number,
transitionConfig?: PageTransitionConfig,
currentPanel?: any
): void {
public navigateToGirlList(themeId: number): void {
if (themeId == null || themeId < 0) {
console.warn("Invalid theme ID for girl list navigation:", themeId);
return;
}
console.log(`Navigating to girl list with theme ID: ${themeId}`);
// 更新选中的主题ID
this.setSelectedThemeId(themeId);
if (transitionConfig) {
const navigationData = {
category: themeId,
withTransition: true,
};
this.navigateWithTransition(
console.log(
`[NavigationManager] Navigating to girl list with theme ID: ${themeId}`
);
// 先检查是否已有GirlListPanel存在
const existingGirlListPanel = this.findExistingGirlListPanel();
if (existingGirlListPanel) {
// 如果面板已存在,重新显示并刷新数据
console.log("[NavigationManager] Reactivating existing GirlListPanel");
this.reactivateGirlListPanel(existingGirlListPanel, themeId);
} else {
// 如果面板不存在,创建新的
console.log("[NavigationManager] Creating new GirlListPanel");
ViewManager.I.openBundlesView(
"GirlListPanel",
themeId,
transitionConfig,
currentPanel,
() => {
GameRootUI.I.hideDefaultView();
{
themeId: themeId,
parentPanel: "ThemePanel", // 标记父页面
},
(girlListPanelNode) => {
// 获取 ThemePanel 实例并设置子页面关系
console.log(
"[NavigationManager] GirlListPanel opened, setting up parent-child relationship"
);
this.setupParentChildRelationship(girlListPanelNode);
}
);
} else {
ViewManager.I.openBundlesView("GirlListPanel", themeId);
}
}
/**
* 查找已存在的GirlListPanel
*/
private findExistingGirlListPanel(): any {
try {
const viewList = (ViewManager.I as any).m_viewList;
if (viewList) {
for (let i = 0; i < viewList.length; i++) {
const view = viewList[i];
if (view && view.isValid && view.name === "GirlListPanel") {
return view;
}
}
}
return null;
} catch (error) {
console.error(
"[NavigationManager] Error finding existing GirlListPanel:",
error
);
return null;
}
}
/**
* 重新激活已存在的GirlListPanel
*/
private reactivateGirlListPanel(panelNode: any, themeId: number): void {
try {
// 重新激活面板
panelNode.active = true;
// 获取面板组件并刷新数据
const girlListComponent = panelNode.getComponent("GirlListPanel");
if (girlListComponent) {
// 如果有刷新方法,调用它来更新主题数据
if (typeof girlListComponent.refreshWithTheme === "function") {
girlListComponent.refreshWithTheme(themeId);
} else if (typeof girlListComponent.Show === "function") {
girlListComponent.Show(themeId);
}
console.log(
"[NavigationManager] GirlListPanel reactivated with theme:",
themeId
);
}
// 重新建立父子关系
this.setupParentChildRelationship(panelNode);
} catch (error) {
console.error(
"[NavigationManager] Error reactivating GirlListPanel:",
error
);
}
}
/**
* 建立父子页面关系的私有方法
* @private
* @param girlListPanelNode GirlListPanel 节点
*/
private setupParentChildRelationship(girlListPanelNode: any): void {
try {
// 查找 ThemePanel 实例
const themePanelNode = this.findThemePanelNode();
if (themePanelNode) {
const themePanelComponent = themePanelNode.getComponent("ThemePanel");
const girlListPanelComponent =
girlListPanelNode.getComponent("GirlListPanel");
if (themePanelComponent && girlListPanelComponent) {
console.log(
"[NavigationManager] Setting up parent-child relationship"
);
themePanelComponent.setChildPanel(girlListPanelComponent);
} else {
console.warn("[NavigationManager] Failed to get panel components");
}
} else {
console.warn("[NavigationManager] ThemePanel not found");
}
} catch (error) {
console.error(
"[NavigationManager] Error setting up parent-child relationship:",
error
);
}
}
/**
* 查找 ThemePanel 节点的私有方法
* @private
* @returns ThemePanel 节点或 null
*/
private findThemePanelNode(): any {
console.log("[NavigationManager] Finding ThemePanel node...");
try {
// 通过 ViewManager 的视图列表查找 ThemePanel
const viewList = (ViewManager.I as any).m_viewList;
if (viewList) {
for (let i = 0; i < viewList.length; i++) {
const view = viewList[i];
if (view && view.isValid && view.name === "ThemePanel") {
console.log("[NavigationManager] Found ThemePanel node");
return view;
}
}
}
console.log("[NavigationManager] ThemePanel not found in view list");
return null;
} catch (error) {
console.error("[NavigationManager] Error finding ThemePanel:", error);
return null;
}
}
/**
* 处理导航时 ThemePanel 子页面的隐藏逻辑
* @private
*/
private handleThemePanelChildPanelsOnNavigation(): void {
console.log(
"[NavigationManager] Handling ThemePanel child panels on navigation"
);
const themePanelNode = this.findThemePanelNode();
if (themePanelNode) {
const themePanelComponent = themePanelNode.getComponent("ThemePanel");
if (themePanelComponent && themePanelComponent.closeChildPanel) {
console.log("[NavigationManager] Closing ThemePanel child panels");
themePanelComponent.closeChildPanel();
}
}
}
@@ -316,7 +834,11 @@ export class NavigationManager {
console.warn("Invalid role ID for chat navigation:", roleId);
return;
}
GameRootUI.I.hideDefaultView();
// 更新选中的角色ID
this.setSelectedGirlId(roleId);
// NavigationPanel 始终显示,不需要隐藏 DefaultView
console.log(`Navigating to chat with role ID: ${roleId}`);
if (transitionConfig) {
@@ -357,6 +879,12 @@ export class NavigationManager {
return;
}
// 更新选中的角色ID和主题ID
this.setSelectedGirlId(roleId);
if (categoryId != null) {
this.setSelectedThemeId(parseInt(categoryId));
}
const navigationData = {
categoryId: categoryId,
roleId: roleId,
@@ -418,6 +946,9 @@ export class NavigationManager {
return;
}
// 更新选中的角色ID
this.setSelectedGirlId(roleId);
console.log(`Navigating to girl detail with role ID: ${roleId}`);
if (transitionConfig) {