文档管理中心

Navigation分栏开发

Navigation作为一个容器组件,提供了两种布局样式:单栏布局、分栏布局。分栏布局一般适用于宽屏设备,在分栏布局下,导航栏(navBar)会固定显示, 子页面(NavDestination)通过导航控制器(NavPathStack)切换显示, 在导航栏和子页面之间有一条分割线, 可以通过分割线拖拽控制左右显示的比例。架构图详见Navigation基础架构介绍。

分栏相关接口介绍

mode

mode属性用于控制Navigation的显示模式,有四种模式:单栏,分栏,自适应,根据高宽比自适应。

图1 单栏(NavigationMode.Stack)效果

图2 分栏(NavigationMode.Split)效果

图3 自适应(NavigationMode.Auto)效果

图4 根据高宽比自适应(NavigationMode.AUTO_WITH_ASPECT_RATIO)效果

navBarPosition用于控制导航栏显示的位置,用navBarPosition控制导航栏显示位置时,会被系统语言所影响。比如,在以汉语、英语为代表的LTR语言体系下,NavBarPosition.Start指代的是导航栏出现在左侧,而在以阿拉伯语为代表的RTL语言体系下,NavBarPosition.Start则指代导航栏出现在右侧。类似的效果也出现在NavBarPosition.End上。

NavBarPosition.Start

图5 系统语言为LTR时NavBarPosition.Start效果

图6 系统语言为RTL时NavBarPosition.Start效果

NavBarPosition.End

图7 系统语言为LTR时NavBarPosition.End效果

图8 系统语言为RTL时NavBarPosition.End效果

enableDragBar

enableDragBar用于控制是否显示分栏的拖动按钮。

图9 enableDragBar为false效果

图10 enableDragBar为true

navBarWidth用于控制导航栏的宽度。

navBarWidthRange用于设置导航栏宽度可调整的范围。

minContentWidth

minContentWidth用于控制分栏子页的最小宽度;分栏模式导航栏和子页中间会有一个分割线,在可调范围内,用户可以通过拖动分割线来调整导航栏和子页的显示大小。

hideNavBar

hideNavBar用于控制导航栏的显示状态,默认值为false。如果同时将mode配置为NavigationMode.Split且hideNavBar设置为true,则实际效果会显示为单栏。

enableModeChangeAnimation

enableModeChangeAnimation用于控制是否开启单双栏切换的动画,默认开启。

splitPlaceholder

splitPlaceholder用于设置分栏模式下内容区的默认占位页。分栏模式在默认情况下,栈中没有页面时内容区展示空白,可使用此接口设置此区域的UI布局。

需要注意的是,占位页仅作为UI展示页,仅分栏模式空栈的情况下才展示,不受路由栈管理也不可获焦和响应事件。

分栏开发示例

以开发一个新闻app的demo来演示如何使用Navigation分栏相关接口。

  1. 新闻主页内容会放到左侧NavBar中,其中内容是一个新闻列表,用户点击每一条新闻标题时,右边会push一个详情页,用来展示新闻的信息。

  2. 给左侧NavBar设置一个宽度范围,右侧子页区域也设置一个最小宽度。

配置的路由表:

收起
自动换行
深色代码主题
复制
  1. {
  2. "routerMap": [
  3. {
  4. "name": "NewsDetail",
  5. "pageSourceFile": "src/main/ets/pages/navigation/splitmode/NewsDetail.ets",
  6. "buildFunction": "NewsDetailPageBuilder",
  7. "data": {
  8. "description": "this is NewsDetail"
  9. }
  10. }
  11. ]
  12. }

子页代码:

收起
自动换行
深色代码主题
复制
  1. // 自定义的参数类型,用于在push页面时给子页传递参数
  2. export class NewsItem {
  3. public title: string;
  4. public overview: string;
  5. public content: string;
  6. constructor(title: string, overview: string, content: string) {
  7. this.title = title;
  8. this.overview = overview;
  9. this.content = content;
  10. }
  11. }
  12. @Builder
  13. export function NewsDetailPageBuilder() {
  14. NewsDetail()
  15. }
  16. @Component
  17. struct NewsDetail {
  18. @State title: string = '';
  19. @State content: string = '';
  20. build() {
  21. NavDestination() {
  22. Column() {
  23. Text(this.content)
  24. }
  25. }
  26. .title(this.title)
  27. .backgroundColor('#fff6e3c8')
  28. .onReady((ctx: NavDestinationContext) => {
  29. // 在onReady生命周期拿到传来的页面参数
  30. let param = ctx.pathInfo.param as NewsItem;
  31. this.title = param?.title;
  32. this.content = param?.content;
  33. })
  34. }
  35. }

主页代码:

收起
自动换行
深色代码主题
复制
  1. import { NewsItem } from './NewsDetail'
  2. @Component
  3. struct NewsHome {
  4. private newsItemArray: Array<NewsItem> = [];
  5. private stack: NavPathStack | undefined = undefined;
  6. aboutToAppear(): void {
  7. // 这里省略了从网络获取新闻信息的过程
  8. for (let i = 0; i < 50; i++) {
  9. this.newsItemArray.push(new NewsItem(`新闻标题${i + 1}`, `新闻概述${i + 1}`, `新闻详情${i + 1}`))
  10. }
  11. let info = this.queryNavigationInfo();
  12. this.stack = info?.pathStack;
  13. }
  14. build() {
  15. List() {
  16. ForEach(this.newsItemArray, (item: NewsItem, index: number) => {
  17. ListItem() {
  18. Column() {
  19. Text(`${item.title}`).margin(15).fontSize(25).fontColor(Color.Black)
  20. Text(`${item.overview}`).fontSize(13).fontColor(Color.Gray)
  21. }.margin({bottom: 15}).backgroundColor('#eeeeee').width('100%')
  22. .borderRadius(15).height(120).onClick(() => {
  23. // 用户点击某一个新闻标签时,就在右侧子页区域push一个NavDestination页面,用来展示新闻详情
  24. this.stack?.pushPath({name: 'NewsDetail', param: item})
  25. })
  26. }.width('100%')
  27. }, (item: NewsItem, index: number) => {
  28. return item.title;
  29. })
  30. }.width('100%').height('100%').padding(15)
  31. }
  32. }
  33. @Entry
  34. @Component
  35. struct Index {
  36. private stack: NavPathStack = new NavPathStack();
  37. @State navWidth: number = 100;
  38. build() {
  39. RelativeContainer() {
  40. Navigation(this.stack) {
  41. NewsHome().width('100%').height('100%')
  42. }
  43. .mode(NavigationMode.Split)
  44. .enableDragBar(true)
  45. .hideNavBar(false)
  46. .navBarWidthRange([100, 700]) // 指定NavBar区域的宽度范围
  47. .minContentWidth(100) // 指定子页区域的最小宽度
  48. .hideTitleBar(true)
  49. .hideToolBar(true)
  50. .height('100%')
  51. .width(`${this.navWidth}%`)
  52. .alignRules({
  53. top: { anchor: '__container__', align: VerticalAlign.Top },
  54. left: { anchor: '__container__', align: HorizontalAlign.Start }
  55. })
  56. }
  57. }
  58. }

图11 运行效果