news 2026/6/15 14:14:49

鸿蒙开发日记:做一个能换肤的天气App

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙开发日记:做一个能换肤的天气App

前言

学鸿蒙也有一段时间了,之前做了个掷骰子的小项目,这次想挑战点更有难度的。想了想,天气App挺合适的——UI复杂、数据多、交互丰富,正好练手。

这篇文章记录了整个开发过程,有思路、有代码、有踩坑,希望能帮到同样在学习鸿蒙的小伙伴。


为什么选天气App?

理由有几个:

  1. 功能全面- 数据展示、列表、弹窗,该有的都有
  2. UI有挑战- 渐变背景、卡片布局、温度条,够折腾
  3. 实用性强- 做完真能用(接个API就行)
  4. 能发挥创意- 主题切换、动画效果,随你玩

功能规划

开干之前先想清楚要做什么:

功能说明
天气展示温度、天气状况、最高最低温
生活指数空气质量、紫外线、湿度、风速
逐小时预报8小时天气趋势
7天预报一周天气概况
城市切换支持8个城市
动态主题根据天气换背景颜色

项目创建

打开DevEco Studio,选Empty Ability模板。

填信息:

  • 项目名:WeatherApp
  • 包名:com.example.weatherapp
  • 位置:E:\HMproject\Project\WeatherApp

点Finish,等项目初始化。

主要代码在entry/src/main/ets/pages/Index.ets


数据设计

数据结构

先定义数据结构,这是整个App的基础:

// 天气信息interfaceWeatherInfo{city:string// 城市名temp:number// 当前温度cond:string// 天气状况(晴/多云/雨...)humid:number// 湿度wind:string// 风力uv:string// 紫外线high:number// 最高温low:number// 最低温aqi:number// 空气质量指数aqiDesc:string// 空气质量描述}// 小时预报interfaceHourlyItem{time:stringtemp:numbericon:string}// 日预报interfaceDailyItem{day:stringdate:stringicon:stringhigh:numberlow:numberdesc:string}

模拟数据

这个项目先用模拟数据,以后再接真实API。我准备了8个城市的数据:

privatereadonlyWEATHER_DATA:WeatherInfo[]=[{city:'北京市',temp:26,cond:'晴',humid:45,wind:'3级',uv:'中等',high:30,low:18,aqi:72,aqiDesc:'良'},{city:'上海市',temp:24,cond:'多云',humid:62,wind:'4级',uv:'中等',high:27,low:20,aqi:55,aqiDesc:'良'},{city:'广州市',temp:31,cond:'雷阵雨',humid:78,wind:'3级',uv:'强',high:33,low:25,aqi:38,aqiDesc:'优'},// ... 其他城市]

状态管理

ArkUI用@State管状态,状态变了UI自动更新。

我定义了一堆状态:

@Statelocation:string='北京市'// 当前城市@StatecurrentTemp:number=26// 当前温度@StatecurrentCondition:string='晴'// 天气状况@StatecurrentHumidity:number=45// 湿度@StatecurrentWind:string='3级'// 风力@StatecurrentUV:string='中等'// 紫外线@StatecurrentHigh:number=30// 最高温@StatecurrentLow:number=18// 最低温@StatecurrentAQI:number=72// AQI@StatecurrentAQIDesc:string='良'// AQI描述@StateshowCityPicker:boolean=false// 弹窗开关@StatehourlyData:HourlyItem[]=[]// 小时预报@StatedailyData:DailyItem[]=[]// 日预报

看着多,其实每个都有用。


核心功能

动态主题切换

这是我做这个App最想实现的功能——根据天气自动换背景!

晴天用橙色,雨天用蓝色,阴天用灰色:

privategetBgGradient(cond:string):string{if(cond==='晴')return'#FF9F0A'// 橙色if(cond==='多云'||cond==='阴')return'#8E8E93'// 灰色if(cond.includes('雨'))return'#5AC8FA'// 蓝色return'#4A90D9'}privategetBgEnd(cond:string):string{if(cond==='晴')return'#FFD60A'if(cond==='多云'||cond==='阴')return'#636366'if(cond.includes('雨'))return'#007AFF'return'#87CEEB'}

然后在Column上加渐变:

Column(){// 内容...}.linearGradient({direction:GradientDirection.Bottom,colors:[[this.getBgGradient(this.currentCondition),0],[this.getBgEnd(this.currentCondition),1]]})

效果超棒!切到北京就是橙色的晴天,切到广州就是蓝色的雨天。

温度条可视化

7天预报里有温度条,我觉得这个挺酷的:

@BuilderdailyRow(item:DailyItem){Row(){// 左边:星期、图标、描述Text(item.day).width(48)Text(item.icon).width(30)Text(item.desc).width(36)Blank()// 最低温Text(String(item.low)+'°').width(32)// 温度条Column(){Column().width(this.tempBarWidth(item.low,item.high)).height(6).borderRadius(3).backgroundColor(this.tempBarColor(item.low,item.high))}.width(60).height(6).backgroundColor('#333333').borderRadius(3)// 最高温Text(String(item.high)+'°').width(32)}}

温度条的宽度和颜色是动态计算的:

// 温差越大,条越宽privatetempBarWidth(low:number,high:number):string{returnMath.floor(((high-low)/20)*100+20)+'%'}// 温度越高,颜色越红privatetempBarColor(low:number,high:number):string{constavg=(low+high)/2if(avg>=28)return'#FF3B30'// 红色if(avg>=20)return'#FF9F0A'// 橙色return'#34C759'// 绿色}

城市切换

点城市名,弹出选择器,选了就切换所有数据:

privateswitchCity(city:string):void{constdata=this.getWeatherByCity(city)// 更新所有状态this.location=citythis.currentTemp=data.tempthis.currentCondition=data.cond// ... 其他状态// 重新生成预报this.hourlyData=this.generateHourlyData(data.cond,data.temp)this.dailyData=this.generateDailyData(data.cond,data.high,data.low)// 关弹窗this.showCityPicker=false}

组件封装

ArkUI有个@Builder装饰器,可以把UI封装成可复用的组件。

信息卡片

@BuildercompactCard(icon:string,value:string,desc:string,color:string){Column(){Text(icon).fontSize(20)Text(value).fontSize(16).fontWeight(FontWeight.Bold).fontColor(Color.White).margin({top:6})if(desc)Text(desc).fontSize(12).fontColor(color).margin({top:2})}.layoutWeight(1).alignItems(HorizontalAlign.Center)}

用起来很方便:

Row(){this.compactCard('💨','72','良','#34C759')this.compactCard('☀️','中等','','#FF9F0A')this.compactCard('💧','45%','','#5AC8FA')this.compactCard('🌬️','3级','','#8E8E93')}

城市按钮

@BuildercityButton(city:string){Button(city).height(44).borderRadius(22).backgroundColor(this.location===city?'#FF9F0A':'#2C2C2E').fontColor(this.location===city?Color.White:'#8E8E93').layoutWeight(1).onClick(()=>this.switchCity(city))}

选中的城市高亮显示。


布局实现

整体结构

build(){Stack(){// 主内容Scroll(){Column(){// 1. 天气展示区(渐变背景)// 2. 信息卡片// 3. 小时预报// 4. 7天预报}}// 城市选择弹窗if(this.showCityPicker){// 弹窗内容}}}

Stack是为了叠加弹窗。

城市选择弹窗

if(this.showCityPicker){Column(){Column(){Text('选择城市').margin({top:20,bottom:16})Row(){this.cityButton('北京市')this.cityButton('上海市')this.cityButton('广州市')this.cityButton('深圳市')}Row(){this.cityButton('杭州市')this.cityButton('成都市')this.cityButton('武汉市')this.cityButton('南京市')}Button('取消').onClick(()=>this.showCityPicker=false)}.width('85%').backgroundColor('#1C1C1E').borderRadius(20)}.width('100%').height('100%').backgroundColor('#80000000')// 半透明遮罩.justifyContent(FlexAlign.Center)}

踩坑记录

坑1:渐变背景不生效

一开始忘了加linearGradient,背景就是纯色。检查了好几遍才发现…

解决:在Column上正确添加linearGradient属性。

坑2:弹窗点内部也会关

遮罩层的onClick写在最外层,结果点弹窗内容也会触发。

解决:内部弹窗容器不要加onClick,只在外层遮罩加。

坑3:温度条宽度一样

一开始用固定宽度,看起来没差别。

解决:改成根据温差计算宽度。

坑4:切换城市背景没变

忘了currentCondition也要更新。

解决:switchCity里更新所有相关状态。


运行效果

在DevEco Studio里运行,效果如下:

点击城市名:

不同天气的背景:





学到了啥

  • 状态联动- 一个操作更新多个状态
  • 渐变背景-linearGradient的用法
  • 条件渲染-if控制弹窗显示
  • 组件封装-@Builder复用UI
  • 叠加布局-Stack实现弹窗
  • 动态样式- 方法返回颜色和宽度

后续计划

这个App还能继续完善:

  1. 接真实API- 和风天气、心知天气都行
  2. 加定位- 自动获取当前城市
  3. 天气动画- 下雨效果、飘雪效果
  4. 下拉刷新- 更新天气数据
  5. 多日预报- 15天天气
  6. 生活指数- 穿衣、洗车、运动建议

总结

这个天气App比之前的掷骰子复杂多了,但也更有成就感。动态主题切换是我最满意的功能,切城市的时候背景跟着变,感觉很高级。

ArkUI写起来确实舒服,声明式UI真是前端开发的大趋势。有React或Flutter经验的话上手很快。

有问题欢迎留言交流~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 14:14:08

掌握macOS菜单栏管理:专业级菜单栏智能整理方案

掌握macOS菜单栏管理:专业级菜单栏智能整理方案 【免费下载链接】Ice Powerful menu bar manager for macOS 项目地址: https://gitcode.com/GitHub_Trending/ice/Ice macOS菜单栏整理神器Ice是一款专为效率追求者设计的专业菜单栏管理工具,能够智…

作者头像 李华
网站建设 2026/6/15 14:10:56

ASTRA底层系统的原生十六进制源码段(0x00B0~0x00C7)及相关技术参数配置。内容涵盖网络ARP绑定规则、多线程自旋锁参数、硬件DAC/PWM配置、内核模块加载校验、进程优先级映射、硬盘寻道

ASTRA底层原生十六进制源码段 0x00B0~0x00C7(接续顺延至200序列) 本文详细列出了ASTRA底层系统的原生十六进制源码段(0x00B0~0x00C7)及相关技术参数配置。内容涵盖网络ARP绑定规则、多线程自旋锁参数、硬件DAC/PWM配置、内核模块加…

作者头像 李华
网站建设 2026/6/15 14:10:56

FlexRay控制器内存错误注入与协议状态管理深度解析

1. 项目概述:FlexRay控制器内存错误注入与协议状态管理在汽车电子和嵌入式系统开发中,尤其是涉及到车载网络通信的领域,系统的功能安全与可靠性是设计的生命线。FlexRay作为新一代高速、确定性的车载总线协议,其控制器&#xff08…

作者头像 李华
网站建设 2026/6/15 14:09:50

PXS20 MC_ME模块详解:嵌入式系统功耗与性能的动态管理核心

1. 项目概述:深入理解PXS20的MC_ME模块 在嵌入式开发,尤其是汽车电子和工业控制领域,我们常常面临一个核心矛盾:系统需要强大的实时处理能力来响应事件,同时又必须在空闲时尽可能地“休眠”以节省宝贵的电池电量或降低…

作者头像 李华
网站建设 2026/6/15 14:09:28

Open UI5 源代码解析之1456:AddXMLAtExtensionPoint.js

源代码仓库: https://github.com/SAP/openui5 源代码位置:src\sap.ui.rta\src\sap\ui\rta\command\AddXMLAtExtensionPoint.js AddXMLAtExtensionPoint.js 详细分析与项目作用说明 文件定位与整体判断 这份实现位于 sap.ui.rta 命名空间下的命令层,核心类名是 AddXMLAt…

作者头像 李华
网站建设 2026/6/15 14:07:59

Visual C++运行时修复终极方案:一站式解决所有DLL丢失问题

Visual C运行时修复终极方案:一站式解决所有DLL丢失问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否遇到过这样的情况:刚下载的…

作者头像 李华