鸿蒙应用开发之页面导航,router不推荐了拥抱Navigation
Navigation组件是ArkUI中的路由容器,通常作为首页根容器使用,由导航页(NavBar)和子页(NavDestination)组成。导航页包含标题栏、菜单栏、内容区和工具栏,可通过hideNavBar隐藏;子页由标题栏、菜单栏和内容区构成。两者可通过路由自由切换,且导航页不在页面栈中。 典型应用场景是Tabs+Navigation组合实现多级页面导航:Tabs控制底部导航栏,Naviga
·
Navigation 介绍
Navigation是路由容器组件,一般作为首页的根容器。Navigation组件主要包含导航页(NavBar)和子页(NavDestination)。导航页由标题栏(Titlebar,包含菜单栏menu)、内容区(Navigation子组件)和工具栏(Toolbar)组成,其中导航页可以通过hideNavBar属性进行隐藏,导航页不存在页面栈中,导航页和子页,以及子页之间可以通过路由操作进行切换。
总结一下
:::info
- Navigation是一个容器组件,一般作为页面的根容器
- Navigation组件主要包含导航页和子页
- 导航页组成:标题栏、菜单栏、内容区(Navigation子组件)、工具栏组件
- 子页组成:标题栏、菜单栏、内容区(NavDestination子组件)组成
:::
Navigation 入门案例
案例需求
- 新建一个导航页(NavigationPage),导航页要求包含标题栏、菜单栏、工具栏、内容区
- 新建一个子页(NavDestinationPage)
- 点击导航页内容区按钮时,跳转到子页
- 在子页内容区点击按钮时,跳转到导航页
代码实现
- 导航页代码
import { NavDestinationPage } from './NavDestinationPage'
@Entry
@Component
struct NavgationPage {
//导航页标题
title:string = '导航页标题'
//导航页菜单按钮
menus: NavigationMenuItem[] = [
{
value: 'aaa', //菜单标题
icon: './image/star.png', //菜单图标
action: () => {} //菜单动作
},
{
value: 'bbb', icon: './image/star.png', action: () => {}
},
{
value: 'ccc', icon: './image/star.png', action: () => {}
},
{
value: 'ddd', icon: './image/star.png', action: () => {}
}
]
//导航页工具栏
toolbar: ToolbarItem[] = [
{
value: 'aaa', icon: './image/star.png', action: () => {}
},
{
value: 'bbb', icon: './image/star.png', action: () => {}
},
{
value: 'ccc', icon: './image/star.png', action: () => {}
},
{
value: 'ddd', icon: './image/star.png', action: () => {}
},
]
//导航路由栈
@Provide navPathStack: NavPathStack = new NavPathStack()
@Builder
NavigationRouter(name:string, params?:string){
if (name === 'NavDestination'){
NavDestinationPage()
}
}
build() {
Navigation(this.navPathStack) {
Column({ space: 15 }) {
Text('Navigation内容区').fontSize(30)
Button('点击跳转到子页')
.onClick(() => {
this.navPathStack.pushPathByName('NavDestination','aaa')
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Pink)
}
.title(this.title) //设置标题
.menus(this.menus) //设置菜单
.toolbarConfiguration(this.toolbar) //设置工具条
.navDestination(this.NavigationRouter) //设置子页面
.titleMode(NavigationTitleMode.Mini) //设置标题模式(Mini、Full)
.hideBackButton(true) //隐藏返回键 //隐藏返回键
}
}
- 子页代码
@Component
export struct NavDestinationPage {
//导航路由栈
@Consume navPathStack: NavPathStack
//子页面标题
@State title:string = '子页面标题'
//子页菜单
menus: NavigationMenuItem[] = [
{
value: 'aaa', icon: './image/star.png', action: () => {}
},
{
value: 'bbb', icon: './image/star.png', action: () => {}
},
{
value: 'ccc', icon: './image/star.png', action: () => {}
}
]
build() {
NavDestination(){
Column(){
Text('NavDestination内容区').fontSize(30)
Button('点击回到导航页')
.onClick(()=>{
this.navPathStack.pop() //弹栈
})
}.width('100%').height('100%').backgroundColor(Color.Orange)
}
.title(this.title) //设置子页标题
.menus(this.menus) //设置子页菜单
}
}
Tabs+Navigation 实现页面导航
经常刷手机的朋友都知道,很多应用的主页都是下边一个工具栏,上边是标题栏 、菜单按钮,中间是显示的内容,点击内容区时跳转到更细节的页面。如:微信、美团、头条等各种App都是采用这种结构。
如下图所示
页面结构
想要实现以上的页面结构,我们可以采用Tabs+Navigation来实现
:::color4
- Tabs:主要用于显示页面的底部导航栏(一级页面)
- Navigation:作为点击底部导航栏时显示页面的容器(二级页面)
- NavDestination:点击页面内容时跳转的细节页面(三级页面)
:::
下面是示意图
案例效果
接下来我们采用以上的页面结构来做一个简单的案例,案例需求如下
:::color4
- 自定义底部导航栏:三个Tab选项(快速入门、课程学习、知识地图)
- 快速入门页面:包含标题栏、内容区是一个List,ListItem是一个字符串,点击ListItem进入子页面
- 快速入门子页面:每一个子页面包含标题栏、内容区,标题栏显示上一页被点击的ListItem字符串
:::
代码实现
为了让代码理解起来实现更加有条理,我们把代码实现步骤拆解一下,按照下面步骤来完成
:::success
- 首先使用Tabs自定义底部导航组件,点击底部导航能够切换导航页面
- 导航页面用了三个自定义组件,分别对应快速入门、课程学习、知识地图
QuickStartPage
快速入门页面CourseLearning
课程学习页面KnowledgeMap
知识地图页面
- 完成
QuickStartPage
快速入门页面- 采用Navigation 作为根容器
- 点击页面内容时,跳转到 NavDestination 子页面
- 后面
CourseLearning
、KnowledgeMap
页面实现步骤模仿QuickStartPage
即可
:::
首页底部导航栏
import { CourseLearning } from '../view/CourseLearning';
import { KnowledgeMap } from '../view/KnowledgeMap';
import { QuickStartPage } from '../view/QuickStartPage';
@Entry
@Component
struct Index {
//当前选中页签索引
@State currentIndex: number = 0
//Tabs控制器
private tabsController: TabsController = new TabsController();
@Builder
tabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
Column() {
Image(this.currentIndex == targetIndex ? selectedImg : normalImg)
.size({ width: 24, height: 24 })
Text(title)
.fontColor(this.currentIndex === targetIndex ? '#0A59F7' : '#999999')
.fontSize(10)
.textAlign(TextAlign.Center)
.lineHeight(14)
.fontWeight(500)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.onClick(() => {
this.currentIndex = targetIndex
this.tabsController.changeIndex(this.currentIndex)
})
}
build() {
Tabs({ controller: this.tabsController, barPosition: BarPosition.End }) {
TabContent() {
QuickStartPage()
}.tabBar(this.tabBuilder('快速入门', 0, $r('app.media.ic_01_on'), $r('app.media.ic_01_off')))
TabContent() {
CourseLearning()
}.tabBar(this.tabBuilder('课程学习', 1, $r('app.media.ic_02_on'), $r('app.media.ic_02_off')))
TabContent() {
KnowledgeMap()
}.tabBar(this.tabBuilder('知识地图', 2, $r('app.media.ic_03_on'), $r('app.media.ic_03_off')))
}.onChange((index) => {
this.currentIndex = index
})
.scrollable(false) //禁止页面滑动切换
.animationDuration(0) //设置页面切换动画时长,0为关闭动画
}
}
快速入门导航页
import { ListItemDetail } from './ListItemDetail';
@Component
export struct QuickStartPage {
@State title: string = '快速入门'
items: string[] = ['HarmonyOS', 'Android', 'IOS', 'MacOS', 'Windows', 'Linux','Open Euler']
//页面栈
@Provide navPathStack: NavPathStack = new NavPathStack()
/**
* 页面路由
* @param name 页面名称
* @param params 页面参数
*/
@Builder
NavgationRouter(name: string, params?: string) {
if (name === 'ListItemDetail'){
ListItemDetail()
}
}
build() {
Navigation(this.navPathStack) {
Column() {
List({ space: 12 }) {
ForEach(this.items, (item: string, index: number) => {
ListItem() {
Text(item).fontSize(18).width('100%').height(50).padding(12)
}.onClick(() => {
this.navPathStack.pushPathByName('ListItemDetail', item)
})
})
}.divider({ strokeWidth: 1, color: Color.Gray })
}.width('100%').height('100%')
.backgroundColor(Color.Pink)
}
.title(this.title)
.mode(NavigationMode.Stack) //单栏模式
.titleMode(NavigationTitleMode.Mini) //标题模式小标题
.hideBackButton(true)
.navDestination(this.NavgationRouter)
}
}
快速入门子页面
@Component
export struct ListItemDetail {
@State title:string = ''
@Consume navPathStack: NavPathStack
aboutToAppear(): void {
this.title = this.navPathStack.getParamByName('ListItemDetail')[0] as string
}
build() {
NavDestination(){
Column(){
Text(`我是子页面: ${this.title}`)
}.width('100%')
.height('100%')
}.title(this.title)
}
}
更多推荐
所有评论(0)