当前位置: 首页 > news >正文

鸿蒙5.0项目开发——鸿蒙天气项目的实现(主页2)

【高心星出品】

文章目录

      • 4.主界面
        • 1. 顶部搜索区域
        • 2. 天气信息卡片
        • 3. 天气预报区域
        • 4. 左侧抽屉菜单
      • 5. 用户交互阶段
      • 5. 数据持久化阶段
      • 6. 错误处理阶段
      • 7. 界面更新阶段
      • 8. 资源释放阶段
      • 最后:

4.主界面

在这里插入图片描述

1. 顶部搜索区域
  • 左侧菜单按钮

  • 中间搜索输入框

  • 右侧搜索按钮

  • 整体采用白色背景,圆角设计

2. 天气信息卡片
  • 城市名称(大号字体)

  • 当前温度(特大号字体)

  • 天气图标(大尺寸)

  • 天气描述

  • 详细信息网格:

  • 湿度

  • 风速

  • PM2.5

  • 空气质量

  • 卡片采用白色背景,带阴影效果

3. 天气预报区域
  • 标题:“未来天气预报”

  • 三个天气卡片:

  • 显示星期

  • 天气图标

  • 温度范围

  • 采用白色背景,带阴影效果

4. 左侧抽屉菜单
  • 顶部标题栏:

  • "搜索历史"标题

  • 编辑/完成按钮

  • 历史记录列表:

  • 城市名称

  • 搜索时间

  • 删除按钮(编辑模式)

  • 空状态显示:

  • 空历史图标

  • "暂无搜索历史"提示

  • 底部清空按钮(编辑模式)

  • 支持滑动关闭

  build() {Stack() {Column() {// 搜索框布局Row() {Image($r('app.media.menu')).width(30).onClick(() => {this.isshow = !this.isshow})TextInput({ placeholder: '输入城市名称' }).width('60%').height(40).backgroundColor(Color.White).borderRadius(8).onChange((value: string) => {this.searchText = value})Button('搜索').width('25%').height(40).backgroundColor('#0083b0').onClick(() => {if (this.searchText.trim()) {this.loadweather(this.searchText.trim(), true)} else {promptAction.showToast({ message: '请输入城市名称' })}})}.width('100%').justifyContent(FlexAlign.SpaceBetween).margin({ bottom: 20 })// 天气信息卡片布局Column() {// 城市名称Text(this.cityName).fontSize(24).fontWeight(FontWeight.Bold).margin({ bottom: 10 })// 温度显示Text(this.temperature).fontSize(48).fontWeight(FontWeight.Bold).margin({ bottom: 10 })// 天气图标Image(getweathericon(this.weatherDesc)).width(100).height(100).margin({ bottom: 10 })// 天气描述Text(this.weatherDesc).fontSize(18).margin({ bottom: 20 })// 详细信息网格布局Grid() {// 湿度信息GridItem() {Column() {Text('湿度').fontSize(14).fontColor('#666666')Text(this.humidity).fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 5 })}}// 风速信息GridItem() {Column() {Text('风速').fontSize(14).fontColor('#666666')Text(this.windSpeed).fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 5 })}}// PM2.5信息GridItem() {Column() {Text('PM2.5').fontSize(14).fontColor('#666666')Text(this.pm25).fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 5 })}}// 空气质量信息GridItem() {Column() {Text('空气质量').fontSize(14).fontColor('#666666')Text(this.quality).fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 5 })}}}.columnsTemplate('1fr 1fr').rowsTemplate('1fr 1fr').width('100%').height(160).margin({ top: 20 })}.width('100%').padding(20).backgroundColor('#FFFFFF').borderRadius(16).shadow({ radius: 6, color: '#1A000000', offsetY: 2 })// 天气预报布局Column() {Text('未来天气预报').fontSize(20).fontWeight(FontWeight.Bold).margin({ bottom: 15 })// 未来三天天气预报Row() {// 按照引用传值才会引起ui刷新this.ForecastItem({ day: this.day1week, tempe: this.day1wendu, type: this.day1type })this.ForecastItem({ day: this.day2week, tempe: this.day2wendu, type: this.day2type })this.ForecastItem({ day: this.day3week, tempe: this.day3wendu, type: this.day3type })}.width('100%').justifyContent(FlexAlign.SpaceBetween)}.width('100%').padding(20).backgroundColor('#FFFFFF').borderRadius(16).margin({ top: 20 }).shadow({ radius: 6, color: '#1A000000', offsetY: 2 })}.width('100%').height('100%').padding(20).backgroundColor('#F5F5F5').onClick(() => {this.isshow = false})// 左侧抽屉布局if (this.isshow) {Column() {// 顶部标题栏布局Row() {if (this.searchHistory.length > 0) {Text('搜索历史').fontSize(20).fontWeight(FontWeight.Bold)}Blank()if (this.searchHistory.length > 0) {Text(this.isEditing ? '完成' : '编辑').fontSize(16).fontColor('#0083b0').onClick(() => {this.isEditing = !this.isEditing// 编辑完成后清除要删除的idif (!this.isEditing) {this.delids.clear()}})}}.width('100%').height(50).padding(16).margin({ top: 20 }).backgroundColor('#FFFFFF')// 搜索历史为空时的显示if (this.searchHistory.length === 0) {Column() {Image($r('app.media.empty_history')).width(80).height(80).margin({ bottom: 16 })Text('暂无搜索历史').fontSize(16).fontColor('#999999')}.width('100%').height('100%').justifyContent(FlexAlign.Center)} else {// 搜索历史列表布局List({ space: 10 }) {ForEach(this.searchHistory, (item: SearchHistoryItem) => {ListItem() {Row() {Row({ space: 20 }) {Text(item.keyword).fontSize(16).fontColor(Color.Black)Text(item.timestamp).fontSize(14).fontColor('#555555').margin({ top: 4 })}.onClick(async () => {await this.loadweather(item.keyword, false)this.isshow = false}).layoutWeight(1)// 编辑模式下显示删除按钮if (this.isEditing) {Image($r('app.media.delete')).width(20).height(20).margin({ left: 16 }).onClick(() => {this.deleteHistoryItem(item.id as number)}).transition(this.effect1)}}.width('100%').padding(15)}.translate({ x: this.delids.has(item.id) ? '-100%' : '0%' })})}.width('100%').layoutWeight(1).margin({ top: 10 }).divider({ strokeWidth: 2, color: 'rgba(0,0,0,0.4)' })}// 编辑模式下显示清空按钮if (this.searchHistory.length > 0 && this.isEditing) {Button('清空历史记录').width('90%').height(40).margin({ bottom: 16 }).backgroundColor('#FF4D4F').onClick(() => {this.clearHistory()}).transition(this.effect1)}}.width('60%').height('100%').backgroundColor(Color.White).transition(this.effect).borderRadius({ topRight: 20, bottomRight: 20 }).border({ width: 1, color: 'rgba(0,0,100,0.5)' })// 抽屉出现时加载搜索历史.onAppear(() => {let sd = new searchdao(this.context)sd.queryall().then((value) => {this.searchHistory = value}).catch((e: Error) => {console.error('gxxt 查询搜索历史失败: ', e.message)})})// 抽屉滑动关闭处理.onTouch((event) => {if (event.type == TouchType.Down) {this.downxy = { x: event.touches[0].windowX, y: event.touches[0].windowY }} else if (event.type == TouchType.Move) {if (event.touches[0].windowX - (this.downxy.x as number) < 0) {if (event.touches[0].windowX - (this.downxy.x as number) <= -60) {this.isshow = false}}}})}}.width('100%').height('100%').alignContent(Alignment.Start)}

5. 用户交互阶段

  1. 搜索功能:

    • 用户输入城市名称

    • 点击搜索按钮

    • 加载对应城市天气

    • 保存搜索记录

     Button('搜索').width('25%').height(40).backgroundColor('#0083b0').onClick(() => {if (this.searchText.trim()) {this.loadweather(this.searchText.trim(), true)} else {promptAction.showToast({ message: '请输入城市名称' })}})
    
  2. 历史记录管理:

    • 点击菜单按钮打开侧边栏

    • 显示搜索历史列表

    • 支持编辑模式切换

    • 可以删除单条记录或清空所有记录

 // 左侧抽屉布局if (this.isshow) {Column() {// 顶部标题栏布局Row() {if (this.searchHistory.length > 0) {Text('搜索历史').fontSize(20).fontWeight(FontWeight.Bold)}Blank()if (this.searchHistory.length > 0) {Text(this.isEditing ? '完成' : '编辑').fontSize(16).fontColor('#0083b0').onClick(() => {this.isEditing = !this.isEditing// 编辑完成后清除要删除的idif (!this.isEditing) {this.delids.clear()}})}}.width('100%').height(50).padding(16).margin({ top: 20 }).backgroundColor('#FFFFFF')// 搜索历史为空时的显示if (this.searchHistory.length === 0) {Column() {Image($r('app.media.empty_history')).width(80).height(80).margin({ bottom: 16 })Text('暂无搜索历史').fontSize(16).fontColor('#999999')}.width('100%').height('100%').justifyContent(FlexAlign.Center)} else {// 搜索历史列表布局List({ space: 10 }) {ForEach(this.searchHistory, (item: SearchHistoryItem) => {ListItem() {Row() {Row({ space: 20 }) {Text(item.keyword).fontSize(16).fontColor(Color.Black)Text(item.timestamp).fontSize(14).fontColor('#555555').margin({ top: 4 })}.onClick(async () => {await this.loadweather(item.keyword, false)this.isshow = false}).layoutWeight(1)// 编辑模式下显示删除按钮if (this.isEditing) {Image($r('app.media.delete')).width(20).height(20).margin({ left: 16 }).onClick(() => {this.deleteHistoryItem(item.id as number)}).transition(this.effect1)}}.width('100%').padding(15)}.translate({ x: this.delids.has(item.id) ? '-100%' : '0%' })})}.width('100%').layoutWeight(1).margin({ top: 10 }).divider({ strokeWidth: 2, color: 'rgba(0,0,0,0.4)' })}// 编辑模式下显示清空按钮if (this.searchHistory.length > 0 && this.isEditing) {Button('清空历史记录').width('90%').height(40).margin({ bottom: 16 }).backgroundColor('#FF4D4F').onClick(() => {this.clearHistory()}).transition(this.effect1)}}.width('60%').height('100%').backgroundColor(Color.White).transition(this.effect).borderRadius({ topRight: 20, bottomRight: 20 }).border({ width: 1, color: 'rgba(0,0,100,0.5)' })// 抽屉出现时加载搜索历史.onAppear(() => {let sd = new searchdao(this.context)sd.queryall().then((value) => {this.searchHistory = value}).catch((e: Error) => {console.error('gxxt 查询搜索历史失败: ', e.message)})})// 抽屉滑动关闭处理.onTouch((event) => {if (event.type == TouchType.Down) {this.downxy = { x: event.touches[0].windowX, y: event.touches[0].windowY }} else if (event.type == TouchType.Move) {if (event.touches[0].windowX - (this.downxy.x as number) < 0) {if (event.touches[0].windowX - (this.downxy.x as number) <= -60) {this.isshow = false}}}})}}.width('100%').height('100%').alignContent(Alignment.Start)

5. 数据持久化阶段

  1. 搜索历史保存:

    • 每次搜索后自动保存

    • 记录包含关键词和时间戳

    // 抽屉出现时加载搜索历史.onAppear(() => {let sd = new searchdao(this.context)sd.queryall().then((value) => {this.searchHistory = value}).catch((e: Error) => {console.error('gxxt 查询搜索历史失败: ', e.message)})})
    ................................
    /*** 查询所有搜索历史记录* @returns 返回搜索历史记录数组*/async queryall() {// 定义存储搜索历史的数组let datas: SearchHistoryItem[] = []try {// 获取数据库实例let rdb = await getrdb(this.context)// 创建查询条件let predicates = new relationalStore.RdbPredicates(TABLENAME1)// 执行查询let rs = await rdb.query(predicates)// 遍历结果集while (rs.goToNextRow()) {// 将每条记录添加到数组中datas.push({id: rs.getLong(rs.getColumnIndex('id')),keyword: rs.getString(rs.getColumnIndex('keyword')),timestamp: rs.getString(rs.getColumnIndex('timestamp')),})}} catch (e) {console.error('gxxt searchdao 查询失败: ', JSON.stringify(e))}return datas;}
    
  2. 数据更新:

    • 实时更新天气信息

    • 保存用户操作记录

6. 错误处理阶段

  1. 网络错误:

    • 显示错误提示

    • 使用默认数据

  2. 定位失败:

    • 提示用户检查定位设置

    • 使用默认城市

  3. 数据加载失败:

    • 显示错误对话框

    • 提供重试选项

7. 界面更新阶段

  1. 状态变化触发UI更新:

    • 天气数据更新

    • 历史记录变化

    • 编辑模式切换

  2. 动画效果:

    • 侧边栏滑动

    • 加载动画

    • 删除动画

8. 资源释放阶段

  1. 页面关闭时:

    • 清理定时器

    • 保存未保存的数据

    • 释放系统资源

最后:

完整项目:https://download.csdn.net/download/gao_xin_xing/90848357

http://www.xdnf.cn/news/483571.html

相关文章:

  • HarmonyOS 开发之 —— 合理使用动画与转场
  • userfaultfd内核线程D状态问题排查
  • 数学实验(Matlab编程基础)
  • Flutter - 集成三方库:日志(logger)
  • 【深度学习】#11 优化算法
  • 麒麟服务器操作系统安装 MySQL 8 实战指南
  • EC800X_DP-DTU-Q600R 系列开发板介绍
  • QML 动画控制、顺序动画与并行动画
  • 25考研经验贴(11408)
  • 智能呼叫系统中的NLP意图理解:核心技术解析与实战
  • 游戏引擎学习第286天:开始解耦实体行为
  • R1 快开门式压力容器操作证备考练习题及答案
  • 2025程序设计天梯赛补题报告
  • 《数字藏品APP开发:解锁高效用户身份认证与KYC流程》
  • xss-labs靶场第11-14关基础详解
  • 2025认证杯数学建模第二阶段A题完整论文(代码齐全):小行星轨迹预测思路
  • MySQL的 JOIN 优化终极指南
  • RAG-MCP:突破大模型工具调用瓶颈,告别Prompt膨胀
  • Android Studio AI插件与Bolt工具实战指南:从零到一打造智能应用
  • PostgreSQL中的全页写
  • 【python编程从入门到到实践】第十章 文件和异常
  • Spring框架(三)
  • 7.重建大师点云处理教程
  • 每周靶点:PCSK9、Siglec15及文献分享
  • python基础语法(三-中)
  • [Java][Leetcode middle] 238. 除自身以外数组的乘积
  • 学习alpha
  • 【基础】Windows开发设置入门4:Windows、Python、Linux和Node.js包管理器的作用和区别(AI整理)
  • go.mod关于go版本异常的处理
  • 数据治理域——数据同步设计