NAVIGATION及NAVIGATOR的使用2
摘要:ArkUI物联网导航应用实例 该代码实现了一个智能家居灯光控制应用的导航系统,包含主页和详情页两个主要界面。主页采用网格布局展示设备卡片,点击卡片通过共享元素动画平滑过渡到详情页。详情页包含亮度调节滑块和设备控制功能,通过自定义路由栈实现页面导航管理。核心特性包括: 使用Navigation组件实现页面堆栈管理 通过共享元素ID实现图标动画过渡效果 采用@Provide/@Consume机制
·
7. 一个物联网Navigation应用实例

完整代码 (Index.ets)
请直接清空您的 Index.ets 并粘贴以下代码:
//Index.ets
// ==========================================
// 1. 定义详情页组件 (这是一个子组件,不是 Entry)
// =========================================
@Component
struct LampDetailPage {
// 1.1 通过 @Consume 获取父组件注入的路由栈,用于返回操作
@Consume('pageStack') pageStack: NavPathStack;
// 1.2 接收传递过来的参数 (这里我们只传一个字符串标题)
@Prop deviceName: string = '';
@State brightnessValue: number = 50;
build() {
// 1.3 必须使用 NavDestination 作为根节点
NavDestination() {
Column() {
// --- 共享元素区域 ---
// 注意:这里的 id 必须和主页的 id 完全一致 ('shared_lamp_id')
Text('💡')
.fontSize(100) // 详情页字体变大
.id('shared_lamp_id') // 【核心】共享元素 ID
.margin({ top: 50, bottom: 20 })
Text(this.deviceName)
.fontSize(24)
.fontColor('#333333')
// --- 控制区域 ---
Column() {
Row() {
Text('亮度')
.fontSize(16)
Blank()
Text(this.brightnessValue + '%')
.fontSize(16)
.fontColor('#FF9800')
}
.width('100%')
.margin({ bottom: 10 })
Slider({
value: this.brightnessValue,
min: 0,
max: 100,
step: 1
})
.blockColor('#FF9800')
.trackColor('#E0E0E0')
.selectedColor('#FFCC80')
.showSteps(true)
.onChange((value: number) => {
this.brightnessValue = Math.round(value);
})
}
.width('85%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(16)
Blank()
// --- 返回按钮 ---
Button('关闭设备')
.width('80%')
.height(50)
.fontSize(18)
.backgroundColor('#333333')
.onClick(() => {
// 1.4 调用路由栈返回上一页
this.pageStack.pop();
})
.margin({ bottom: 40 })
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
.title('设备控制') // 导航栏标题
.hideBackButton(true) // 隐藏默认返回按钮,使用我们自定义的按钮
}
}
// ==========================================
// 2. 主页组件 (程序的入口)
// ==========================================
@Entry
@Component
struct Index {
// 2.1 创建路由栈实例,并使用 @Provide 向子组件提供
@Provide('pageStack') pageStack: NavPathStack = new NavPathStack();
// 2.2 构建设备卡片的 UI
@Builder
DeviceCard(name: string) {
Column() {
// --- 共享元素源 ---
Text('💡')
.fontSize(50) // 主页字体较小
.id('shared_lamp_id') // 【核心】ID 必须与详情页一致
Text(name)
.fontSize(16)
.margin({ top: 10 })
.fontColor('#666666')
}
.width(140)
.height(160)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({ radius: 10, color: '#1A000000', offsetX: 0, offsetY: 4 })
.onClick(() => {
// 2.3 点击事件:跳转到详情页
// 参数1: 路由名称 (对应 PageMap 中的字符串)
// 参数2: 传递的参数 (这里直接传字符串,避免类型转换错误)
this.pageStack.pushPathByName('LampDetailPage', name);
})
}
// 2.3 路由映射表 (核心逻辑)
// 作用:告诉 Navigation 组件,当路由名字是 'LampDetailPage' 时,应该渲染哪个组件
@Builder
PageMap(name: string, param: Object) {
if (name === 'LampDetailPage') {
// 将 param 转换为 string 传给子组件
LampDetailPage({ deviceName: param as string })
}
}
build() {
Column() {
// 2.4 Navigation 容器组件
Navigation(this.pageStack) {
Column() {
// 顶部标题栏
Text('智能家居中枢')
.fontSize(28)
.width('100%')
.padding({ top: 40, left: 20, bottom: 20 })
// 设备列表
Grid() {
GridItem() {
this.DeviceCard('客厅主灯')
}
GridItem() {
this.DeviceCard('阅读台灯')
}
GridItem() {
this.DeviceCard('氛围灯带')
}
GridItem() {
this.DeviceCard('床头灯')
}
}
.columnsTemplate('1fr 1fr')
.rowsGap(20)
.columnsGap(20)
.width('100%')
.padding(20)
.height('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
.mode(NavigationMode.Stack) // 必须设置为 Stack 模式以支持转场
.navDestination(this.PageMap) // 【核心】注册路由映射
// 隐藏主页默认的导航栏,我们自己写了标题
.hideTitleBar(true)
}
}
}
2. 详情页
// pages/LampDetailPage.ets (注意:这是一个自定义组件,不是 @Entry)
import { DeviceInfo } from './DeviceInfo';
import { NavPathStack } from '@kit.ArkUI';
// 定义接收参数的组件
@Component
export struct LampDetailPage {
// 接收主页传来的参数
@Prop device: DeviceInfo;
// 注入主页的路由栈,实现返回
@Consume('pageInfo') pageStack: NavPathStack;
@State brightness: number = 50;
build() {
NavDestination() {
Column() {
// 顶部:这里必须使用相同的 id 'lamp_icon',实现共享元素过渡
Text('🔦')
.fontSize(80) // 变大了
.id('lamp_icon') // 关键:ID 必须与主页一致
.margin({ top: 50 })
Text(this.device.name + ' - 正在连接...').fontSize(20).margin(10)
// 模拟滑块控制
Column() {
Text('亮度调节')
Slider({ value: this.brightness, min: 0, max: 100 })
.width('80%')
.blockColor(Color.Blue)
.onChange((value: number) => {
this.brightness = value;
})
Text(`${this.brightness}%
代码运行指南与原理解析
1. 如何运行:
◦ 打开 DevEco Studio。
◦ 找到您的 entry/src/main/ets/pages/Index.ets。
◦ 全选删除里面的内容。
◦ 粘贴上面的代码。
◦ 点击 Run (Shift + F10)。
2. 为什么这次不会报错?
◦ 单文件:不再依赖 DeviceInfo.ets 或 LampDetail.ets,避免了“找不到模块”的错误。
◦ 类型安全:PageMap 中将 param 直接作为 string 处理,避免了复杂自定义类的序列化问题。
◦ 标准 API:使用了 @kit.ArkUI 导入,这是 HarmonyOS API 9/10/11 的标准方式。
3. 重点解析:Navigation 的用法
◦ 入口:Navigation(this.pageStack) 是根容器。
◦ 注册:.navDestination(this.PageMap) 绑定了路由映射表。就像一个前台接待员,当你告诉他“我要去 LampDetailPage”时,他会查表然后把对应的页面组件拿出来给你。
◦ 跳转:this.pageStack.pushPathByName('Name', param) 是“买票”的过程。
◦ 共享元素 (id):请注意代码中的 .id('shared_lamp_id')。
◦ 主页里的 Text('💡') 有这个 ID。
◦ 详情页里的 Text('💡') 也有这个 ID。
◦ 系统检测到这两个 ID 相同,就会自动生成动画:主页的灯泡会“飞”到详情页的位置并变大,而不是生硬的页面切换。这是 Navigation 组件最“有趣”的地方。
上面代码也可拆开成两个文件:
// Index.ets
// 引入刚才创建的详情页组件
import { LampDetailPage } from './LampDetailPage';
@Entry
@Component
struct Index {
@Provide('pageStack') pageStack: NavPathStack = new NavPathStack();
@Builder
DeviceCard(name: string) {
Column() {
Text('💡')
.fontSize(50)
.id('shared_lamp_id') // 共享元素 ID,必须与详情页一致
Text(name)
.fontSize(16)
.margin({ top: 10 })
.fontColor('#666666')
}
.width(140)
.height(160)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({ radius: 10, color: '#1A000000', offsetX: 0, offsetY: 4 })
.onClick(() => {
// 执行 Navigation 跳转
this.pageStack.pushPathByName('LampDetailPage', name);
})
}
@Builder
PageMap(name: string, param: Object) {
if (name === 'LampDetailPage') {
// 实例化引入的组件,并传递参数
LampDetailPage({ deviceName: param as string })
}
}
build() {
Column() {
Navigation(this.pageStack) {
Column() {
Text('智能家居中枢')
.fontSize(28)
.width('100%')
.padding({ top: 40, left: 20, bottom: 20 })
Grid() {
GridItem() { this.DeviceCard('客厅主灯') }
GridItem() { this.DeviceCard('阅读台灯') }
GridItem() { this.DeviceCard('氛围灯带') }
GridItem() { this.DeviceCard('床头灯') }
}
.columnsTemplate('1fr 1fr')
.rowsGap(20)
.columnsGap(20)
.width('100%')
.padding(20)
.height('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
.mode(NavigationMode.Stack)
.navDestination(this.PageMap)
.hideTitleBar(true)
}
}
}
// pages/LampDetailPage.ets
// 使用 export 导出,供主页 import 使用
@Component
export struct LampDetailPage {
// 通过 @Consume 获取父组件注入的路由栈
@Consume('pageStack') pageStack: NavPathStack;
@Prop deviceName: string = '';
@State brightnessValue: number = 50;
build() {
NavDestination() {
Column() {
// 共享元素 ID
Text('💡')
.fontSize(100)
.id('shared_lamp_id')
.margin({ top: 50, bottom: 20 })
Text(this.deviceName)
.fontSize(24)
.fontColor('#333333')
Column() {
Row() {
Text('亮度').fontSize(16)
Blank()
Text(this.brightnessValue + '%').fontSize(16).fontColor('#FF9800')
}
.width('100%').margin({ bottom: 10 })
Slider({
value: this.brightnessValue,
min: 0,
max: 100,
step: 1
})
.blockColor('#FF9800')
.trackColor('#E0E0E0')
.selectedColor('#FFCC80')
.showSteps(true)
.onChange((value: number) => {
this.brightnessValue = Math.round(value);
})
}
.width('85%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(16)
Blank()
Button('关闭设备')
.width('80%')
.height(50)
.fontSize(18)
.backgroundColor('#333333')
.onClick(() => {
this.pageStack.pop();
})
.margin({ bottom: 40 })
}
.width('100%')
.height('100%')
.backgroundColor(Color.White)
}
.title('设备控制')
.hideBackButton(true)
}
}
更多推荐

所有评论(0)