HarmonyOS鸿蒙Next应用开发中,如何使得Navigation的split模式右侧始终有个占位页面

HarmonyOS鸿蒙Next应用开发中,如何使得Navigation的split模式右侧始终有个占位页面

当设备较宽时,Navigation的mode会处于Split模式,即双栏模式。在双栏模式下,右侧如果没有页面,那么会处于空白状态。如果要给右边一个占位页面,那么可以用路由拦截来使得栈中始终有一个页面,并将这个页面添加自己想要的占位内容。

下面创建一个“Page01”页面,显示一行文字“这里什么也没有哦!”来提示用户当前没有内容,示例如下:

@Component
struct Page01 {
  pathStack: NavPathStack | undefined = undefined;

  build() {
    NavDestination() {
      Column() {
        Text(`这里什么也没有哦!`)
      }.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
    }.backgroundColor($r('sys.color.mask_fourth'))
    .hideTitleBar(true)
    // 把动画关闭,不然视觉效果差
    .systemTransition(NavigationSystemTransitionType.NONE)
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
    })
  }
}

进入页面时,通过setInterception设置路由拦截,如果是要跳转到navBar(主页面),并且处于Split模式,就向栈中push一个占位页面Page01。

// 设置路由拦截来保持栈中最底层是显示栈中为空的页面
this.pathStack.setInterception({
  willShow: (from: NavDestinationContext | NavBar, to: NavDestinationContext | NavBar, operation: NavigationOperation, isAnimated: boolean) => {
    console.log(`willShow: from ${JSON.stringify(from)}, to ${JSON.stringify(to)}, operation ${operation}, isAnimated ${isAnimated}.`);
    // 如果是要跳转到navBar,并且处于Split模式
    if (to == 'navBar' && this.navigationMode == NavigationMode.Split) {
      this.pathStack.pushPath({ name: 'Page01' }, (from as NavDestinationContext).pathInfo.name != 'Page01');
    }
  }
})

效果如下:

效果

完整示例如下:

@Component
struct Page01 {
  pathStack: NavPathStack | undefined = undefined;

  build() {
    NavDestination() {
      Column() {
        Text(`这里什么也没有哦!`)
      }.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
    }.backgroundColor($r('sys.color.mask_fourth'))
    .hideTitleBar(true)
    // 把动画关闭,不然视觉效果差
    .systemTransition(NavigationSystemTransitionType.NONE)
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
    })
  }
}

@Component
struct Page02 {
  pathStack: NavPathStack | undefined = undefined;

  build() {
    NavDestination() {
      Column() {
        Button('push Page02').width('80%').margin({ top: 10, bottom: 10 })
          .onClick(() => {
            this.pathStack?.pushPath({ name: 'Page02' });
          })
        Button('pop').width('80%').margin({ top: 10, bottom: 10 })
          .onClick(() => {
            this.pathStack?.pop();
          })
      }.width('100%').height('100%')
    }.title('页面2')
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
    })
  }
}

@Entry
@Component
struct Index {
  pathStack: NavPathStack = new NavPathStack();
  navigationMode: NavigationMode = NavigationMode.Auto;

  @Builder
  pagesMap(name: string) {
    if (name == 'Page01') {
      Page01()
    } else if (name == 'Page02') {
      Page02()
    }
  }

  aboutToAppear(): void {
    // 设置路由拦截来保持栈中最底层是显示栈中为空的页面
    this.pathStack.setInterception({
      willShow: (from: NavDestinationContext | NavBar, to: NavDestinationContext | NavBar, operation: NavigationOperation, isAnimated: boolean) => {
        console.log(`willShow: from ${JSON.stringify(from)}, to ${JSON.stringify(to)}, operation ${operation}, isAnimated ${isAnimated}.`);
        // 如果是要跳转到navBar,并且处于Split模式
        if (to == 'navBar' && this.navigationMode == NavigationMode.Split) {
          this.pathStack.pushPath({ name: 'Page01' }, (from as NavDestinationContext).pathInfo.name != 'Page01');
        }
      }
    })
  }

  build() {
    Navigation(this.pathStack) {
      Column() {
        Button('push Page02').width('80%').margin({ top: 10, bottom: 10 })
          .onClick(() => {
            this.pathStack.pushPath({ name: 'Page02' });
          })
        Button('pop').width('80%').margin({ top: 10, bottom: 10 })
          .onClick(() => {
            this.pathStack.pop();
          })
      }.width('100%').height('100%')
    }.title('主页面')
    .titleMode(NavigationTitleMode.Mini)
    .navDestination(this.pagesMap)
    .onNavigationModeChange((mode: NavigationMode) => {
      console.log(`Navigation onNavigationModeChange mode: ${mode}.`);
      this.navigationMode = mode;

      if (this.navigationMode == NavigationMode.Split) {
        // mode切换到Split模式时,如果栈中为空,push一个占位页面
        if (this.pathStack.size() == 0) {
          this.pathStack.pushPath({ name: 'Page01' }, false);
        }
      } else {
        // mode切换到非Split模式时,如果栈中只有一个页面并且为占位页面
        if (this.pathStack.size() == 1 && this.pathStack.getAllPathName()[0] == 'Page01') {
          this.pathStack.pop(false);
        }
      }
    })
  }
}

更多关于HarmonyOS鸿蒙Next应用开发中,如何使得Navigation的split模式右侧始终有个占位页面的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS鸿蒙Next应用开发中,要使Navigation的split模式右侧始终有个占位页面,可以在Navigation组件中使用NavDestination定义右侧页面,并设置split属性为true。通过NavControllernavigate方法指定默认页面,确保右侧始终显示占位内容。具体实现可参考鸿蒙官方文档中关于NavigationNavDestination的配置说明。

更多关于HarmonyOS鸿蒙Next应用开发中,如何使得Navigation的split模式右侧始终有个占位页面的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现Navigation的Split模式右侧占位页面,可以通过路由拦截机制来动态管理页面栈。你的实现方案是正确的,这里补充几点关键说明:

  1. 路由拦截核心逻辑
  • willShow拦截器中检测到跳转至navBar且处于Split模式时,自动压入Page01占位页
  • 通过NavPathStack.pushPath()方法控制页面栈
  1. 模式切换处理
  • 监听onNavigationModeChange事件
  • Split模式激活时检查空栈并自动填充占位页
  • 非Split模式时自动移除冗余占位页
  1. 视觉优化要点
  • 使用systemTransition(NONE)禁用页面过渡动画
  • 设置适当背景色提升视觉体验
  • 隐藏占位页面的标题栏
  1. 注意事项
  • 确保pathStack正确初始化
  • 处理页面栈时要考虑边界条件
  • 拦截器逻辑需保持简洁高效

你的实现方案完整展示了HarmonyOS Navigation在Split模式下的占位页处理方式,这种模式特别适合平板等大屏设备的双栏布局场景。

回到顶部