[HarmonyOS NEXT 实战案例:旅行应用] 进阶篇 - 旅行规划应用的交互功能与状态管理

2025-06-11 23:30:27
107次阅读
0个评论

[HarmonyOS NEXT 实战案例:旅行应用] 进阶篇 - 旅行规划应用的交互功能与状态管理

项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示

引言

在基础篇中,我们学习了如何使用HarmonyOS NEXT的RowSplit组件构建旅行规划应用的基本布局。在本篇进阶教程中,我们将深入探讨旅行规划应用的交互功能和状态管理,包括行程切换、视图模式切换、数据绑定等高级特性。通过掌握这些进阶技巧,你将能够构建出更加实用和用户友好的旅行规划应用。

状态管理概述

在HarmonyOS NEXT中,状态管理是实现交互功能的关键。在我们的旅行规划应用中,主要使用了以下状态变量:

@State selectedDay: number = 0
@State showMap: boolean = false
@State tripDays: TripDay[] = [ /* ... */ ]

这些状态变量的作用如下:

  • selectedDay:记录当前选中的行程索引,初始值为0(第一天)
  • showMap:控制是否显示地图视图,初始值为false(显示详情视图)
  • tripDays:存储所有行程数据,包含多天的行程信息

数据模型与绑定

数据模型定义

在旅行规划应用中,我们定义了两个接口来描述数据结构:

interface TripDay {
    day: string
    date: string
    location: string
    description: string
    hotel: string
    restaurant: string
    image: Resource
    activities: Activity[]
}

interface Activity {
    time: string
    title: string
    icon: Resource
}

这种清晰的数据模型定义有助于我们理解和管理应用的数据流。

数据绑定

在HarmonyOS NEXT中,数据绑定是通过状态变量和UI组件的属性绑定来实现的。以下是一些数据绑定的示例:

1. 行程列表项的选中状态

.backgroundColor(index === this.selectedDay ? '#e8f5e9' : 'transparent')

这里,我们根据index是否等于selectedDay来决定行程列表项的背景色,实现选中效果。

2. 详情区域标题

Text(this.tripDays[this.selectedDay].day + ' · ' + this.tripDays[this.selectedDay].location)

这里,我们根据selectedDay索引从tripDays数组中获取当前选中行程的信息,并显示在标题中。

3. 切换按钮图标

Image(this.showMap ? $r('app.media.big15') : $r('app.media.big14'))

这里,我们根据showMap状态来决定显示哪个图标,实现切换效果。

交互功能实现

1. 行程切换功能

行程切换功能是通过点击左侧行程列表项来实现的:

ForEach(this.tripDays, (item: TripDay, index: number) => {
    Column() {
        // 行程列表项内容
    }
    .onClick(() => this.selectedDay = index)
})

当用户点击一个行程列表项时,会执行.onClick(() => this.selectedDay = index)回调函数,更新selectedDay状态变量。由于selectedDay是一个@State装饰的状态变量,它的变化会触发UI的自动更新,从而实现行程切换功能。

具体的更新包括:

  1. 左侧行程列表项的选中状态(背景色)更新
  2. 右侧详情区域的内容更新,包括标题、图片、描述、活动列表、住宿和餐饮信息

2. 视图模式切换功能

视图模式切换功能是通过点击右侧详情区域顶部的切换按钮来实现的:

Image(this.showMap ? $r('app.media.big15') : $r('app.media.big14'))
    .onClick(() => this.showMap = !this.showMap)

当用户点击切换按钮时,会执行.onClick(() => this.showMap = !this.showMap)回调函数,切换showMap状态变量。由于showMap是一个@State装饰的状态变量,它的变化会触发UI的自动更新,从而实现视图模式切换功能。

具体的更新包括:

  1. 切换按钮图标的更新
  2. 右侧详情区域内容的更新,在地图视图和详情视图之间切换

3. 条件渲染

条件渲染是实现视图模式切换的关键技术。在右侧详情区域,我们使用条件语句根据showMap状态来决定显示地图视图还是详情视图:

if (this.showMap) {
    // 地图视图
    Column() {
        Image($r('app.media.big13'))
            .width('100%')
            .height(300)
            .objectFit(ImageFit.Cover)
            .borderRadius(8)

        Text('地图位置')
            .fontSize(16)
            .margin({ top: 15 })
    }
    .height('100%')
} else {
    // 详情视图
    Scroll() {
        Column() {
            // 详情视图内容
        }
    }
}

showMaptrue时,显示地图视图;当showMapfalse时,显示详情视图。这种条件渲染方式使我们能够在同一个区域显示不同的内容,提高界面的灵活性。

高级状态管理

1. 状态派生

状态派生是指根据一个或多个状态变量计算出新的值。在我们的旅行规划应用中,有多处使用了状态派生:

// 根据selectedDay派生当前行程信息
const currentTrip = this.tripDays[this.selectedDay];

// 派生标题文本
Text(currentTrip.day + ' · ' + currentTrip.location)

// 派生切换按钮图标
Image(this.showMap ? $r('app.media.big15') : $r('app.media.big14'))

状态派生使我们能够根据基本状态计算出更复杂的值,简化代码逻辑。

2. 状态更新与UI刷新

在HarmonyOS NEXT中,当@State装饰的状态变量发生变化时,框架会自动触发UI的更新。这种响应式的状态管理机制使我们能够专注于状态的变化,而不需要手动更新UI。

例如,当用户点击行程列表项时,我们只需要更新selectedDay状态:

.onClick(() => this.selectedDay = index)

框架会自动检测到selectedDay的变化,并更新所有依赖于它的UI部分,包括行程列表项的选中状态和右侧详情区域的内容。

3. 组合状态

组合状态是指多个状态变量共同决定UI的显示。在我们的旅行规划应用中,右侧详情区域的内容是由selectedDayshowMap两个状态变量共同决定的:

  • selectedDay决定显示哪一天的行程信息
  • showMap决定是显示地图视图还是详情视图

这种组合状态使我们能够实现更复杂的UI逻辑,提高应用的交互性。

实战案例:添加新功能

1. 添加行程收藏功能

让我们为旅行规划应用添加一个行程收藏功能。首先,我们需要在TripDay接口中添加一个favorite字段:

interface TripDay {
    day: string
    date: string
    location: string
    description: string
    hotel: string
    restaurant: string
    image: Resource
    activities: Activity[]
    favorite: boolean  // 新增字段
}

然后,在右侧详情区域的顶部操作栏中添加一个收藏按钮:

Row() {
    Text(this.tripDays[this.selectedDay].day + ' · ' + this.tripDays[this.selectedDay].location)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .layoutWeight(1)

    // 收藏按钮
    Image(this.tripDays[this.selectedDay].favorite ? $r('app.media.favorite_filled') : $r('app.media.favorite_outline'))
        .width(24)
        .height(24)
        .margin({ right: 10 })
        .onClick(() => {
            // 创建一个新的数组,避免直接修改状态
            const newTripDays = [...this.tripDays];
            newTripDays[this.selectedDay].favorite = !newTripDays[this.selectedDay].favorite;
            this.tripDays = newTripDays;
        })

    Image(this.showMap ? $r('app.media.big15') : $r('app.media.big14'))
        .width(24)
        .height(24)
        .onClick(() => this.showMap = !this.showMap)
}

这样,用户就可以通过点击收藏按钮来收藏或取消收藏当前行程了。

2. 添加行程筛选功能

让我们为旅行规划应用添加一个行程筛选功能,允许用户筛选出收藏的行程。首先,我们需要添加一个新的状态变量:

@State showFavoritesOnly: boolean = false

然后,在左侧行程列表区域的顶部添加一个筛选按钮:

Row() {
    Text('我的行程')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .layoutWeight(1)

    // 筛选按钮
    Image(this.showFavoritesOnly ? $r('app.media.filter_on') : $r('app.media.filter_off'))
        .width(24)
        .height(24)
        .onClick(() => this.showFavoritesOnly = !this.showFavoritesOnly)
}
.width('100%')
.margin({ top: 20, bottom: 15 })

最后,修改行程列表的渲染逻辑,根据筛选条件显示行程:

ForEach(this.tripDays.filter(trip => !this.showFavoritesOnly || trip.favorite), (item: TripDay, index: number) => {
    // 行程列表项内容
})

这样,当用户点击筛选按钮时,可以切换显示所有行程或只显示收藏的行程。

小结

在本教程中,我们深入探讨了旅行规划应用的交互功能和状态管理。通过使用@State装饰器定义状态变量,我们实现了行程切换、视图模式切换等交互功能。我们还学习了状态派生、状态更新与UI刷新、组合状态等高级状态管理技巧,以及如何添加行程收藏和筛选功能。

收藏00

登录 后评论。没有帐号? 注册 一个。