HarmonyOS ArkTS 实战:实现一个天气查询与生活指数应用
·
HarmonyOS ArkTS 实战:实现一个天气查询与生活指数应用
项目效果
本文使用 HarmonyOS 和 ArkTS 实现一个精美的天气查询与生活指数应用。支持多城市天气、24小时预报、7天预报、生活指数、空气质量、天气动画等功能,蓝色渐变背景,毛玻璃卡片设计。
项目使用 DevEco Studio 开发,适配 API 24 及以上版本。
运行效果

功能介绍
- 当前天气实时展示(温度、天气状况、体感温度)
- 24小时逐小时预报
- 7天天气预报
- 空气质量AQI展示
- 生活指数(穿衣、紫外线、运动、洗车等)
- 多城市管理和切换
- 城市搜索添加
- 天气动画效果
- 日出日落时间
- 风力风向湿度展示
- 降水概率预报
- 下拉刷新天气
- 定位当前城市
- 温度趋势折线图
- 恶劣天气预警
定义数据结构
interface HourlyForecast {
time: string;
temp: number;
icon: string;
desc: string;
}
interface DailyForecast {
date: string;
week: string;
dayIcon: string;
nightIcon: string;
highTemp: number;
lowTemp: number;
desc: string;
windDir: string;
windLevel: string;
}
interface LifeIndex {
name: string;
level: string;
desc: string;
icon: string;
color: string;
}
interface CityWeather {
city: string;
temp: number;
feelsLike: number;
desc: string;
icon: string;
humidity: number;
windDir: string;
windLevel: string;
aqi: number;
aqiLevel: string;
sunrise: string;
sunset: string;
hourly: HourlyForecast[];
daily: DailyForecast[];
lifeIndex: LifeIndex[];
}
初始化页面状态
@State private currentCityIndex: number = 0;
@State private showCityList: boolean = false;
@State private searchCity: string = '';
@State private cities: CityWeather[] = [
{
city: '上海', temp: 28, feelsLike: 31, desc: '多云', icon: '⛅',
humidity: 72, windDir: '东南风', windLevel: '3级', aqi: 58, aqiLevel: '良',
sunrise: '05:12', sunset: '19:02',
hourly: [
{ time: '现在', temp: 28, icon: '⛅', desc: '多云' },
{ time: '15时', temp: 29, icon: '☀️', desc: '晴' },
{ time: '16时', temp: 29, icon: '☀️', desc: '晴' },
{ time: '17时', temp: 28, icon: '⛅', desc: '多云' },
{ time: '18时', temp: 27, icon: '🌆', desc: '多云' },
{ time: '19时', temp: 26, icon: '🌙', desc: '晴' },
],
daily: [
{ date: '今天', week: '周五', dayIcon: '⛅', nightIcon: '🌙', highTemp: 31, lowTemp: 25, desc: '多云', windDir: '东南风', windLevel: '3级' },
{ date: '明天', week: '周六', dayIcon: '☀️', nightIcon: '🌙', highTemp: 33, lowTemp: 26, desc: '晴', windDir: '南风', windLevel: '2级' },
{ date: '周日', week: '周日', dayIcon: '🌧️', nightIcon: '🌧️', highTemp: 29, lowTemp: 24, desc: '小雨', windDir: '东风', windLevel: '4级' },
{ date: '周一', week: '周一', dayIcon: '⛅', nightIcon: '🌙', highTemp: 30, lowTemp: 25, desc: '多云', windDir: '北风', windLevel: '3级' },
{ date: '周二', week: '周二', dayIcon: '☀️', nightIcon: '🌙', highTemp: 32, lowTemp: 26, desc: '晴', windDir: '南风', windLevel: '2级' },
],
lifeIndex: [
{ name: '穿衣', level: '炎热', desc: '建议穿短衫短裙', icon: '👕', color: '#EF4444' },
{ name: '紫外线', level: '强', desc: '涂SPF20+防晒霜', icon: '☀️', color: '#F59E0B' },
{ name: '运动', level: '适宜', desc: '适合户外运动', icon: '🏃', color: '#10B981' },
{ name: '洗车', level: '不宜', desc: '未来有雨', icon: '🚗', color: '#6B7280' },
]
},
{
city: '北京', temp: 32, feelsLike: 35, desc: '晴', icon: '☀️',
humidity: 45, windDir: '北风', windLevel: '2级', aqi: 85, aqiLevel: '良',
sunrise: '05:02', sunset: '19:35',
hourly: [], daily: [], lifeIndex: []
}
];
@State private cityList: string[] = ['上海', '北京', '广州', '深圳', '杭州', '南京', '成都', '重庆', '武汉', '西安'];
核心功能方法
private getAqiColor(aqi: number): string {
if (aqi <= 50) return '#10B981';
if (aqi <= 100) return '#F59E0B';
if (aqi <= 150) return '#F97316';
if (aqi <= 200) return '#EF4444';
return '#7C3AED';
}
private switchCity(index: number): void {
this.currentCityIndex = index;
this.showCityList = false;
}
private addCity(): void {
if (this.searchCity && !this.cities.find(c => c.city === this.searchCity)) {
const newCity: CityWeather = {
city: this.searchCity, temp: 26, feelsLike: 28, desc: '晴', icon: '☀️',
humidity: 60, windDir: '南风', windLevel: '2级', aqi: 45, aqiLevel: '优',
sunrise: '05:30', sunset: '19:00', hourly: [], daily: [], lifeIndex: []
};
this.cities = [...this.cities, newCity];
this.cityList = [...this.cityList, this.searchCity];
this.searchCity = '';
}
}
@Builder 可复用组件
@Builder
HourlyItem(hour: HourlyForecast) {
Column({ space: 8 }) {
Text(hour.time)
.fontSize(12)
.fontColor('rgba(255,255,255,0.8)')
Text(hour.icon)
.fontSize(24)
Text(`${hour.temp}°`)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
}
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
}
@Builder
DailyItem(day: DailyForecast) {
Row({ space: 12 }) {
Text(day.date)
.fontSize(14)
.fontColor(Color.White)
.width(50)
Text(day.dayIcon)
.fontSize(22)
Text(day.desc)
.fontSize(13)
.fontColor('rgba(255,255,255,0.8)')
.layoutWeight(1)
Text(`${day.lowTemp}°`)
.fontSize(14)
.fontColor('rgba(255,255,255,0.7)')
.width(30)
.textAlign(TextAlign.End)
Text(`${day.highTemp}°`)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
.width(30)
.textAlign(TextAlign.End)
}
.width('100%')
.padding({ top: 12, bottom: 12 })
}
@Builder
LifeIndexItem(index: LifeIndex) {
Column({ space: 6 }) {
Text(index.icon)
.fontSize(24)
Text(index.name)
.fontSize(12)
.fontColor(Color.White)
Text(index.level)
.fontSize(11)
.fontColor(index.color)
.fontWeight(FontWeight.Medium)
}
.width('100%')
.padding(12)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(12)
}
完整build()页面布局
build() {
const weather = this.cities[this.currentCityIndex];
Stack({ alignContent: Alignment.Top }) {
// 渐变背景
Column()
.width('100%')
.height('100%')
.linearGradient({
angle: 180,
colors: [['#0EA5E9', 0], ['#38BDF8', 0.5], ['#7DD3FC', 1]]
})
Column() {
// 顶部城市栏
Row() {
Text('📍')
.fontSize(20)
Text(weather.city)
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
Text('⌄')
.fontSize(16)
.fontColor(Color.White)
Blank()
Text('🔍')
.fontSize(20)
.onClick(() => this.showCityList = true)
}
.width('100%')
.padding(20)
Scroll() {
Column({ space: 20 }) {
// 当前温度
Column({ space: 4 }) {
Text(weather.icon)
.fontSize(72)
Text(`${weather.temp}°`)
.fontSize(72)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text(`${weather.desc} 体感${weather.feelsLike}°`)
.fontSize(16)
.fontColor('rgba(255,255,255,0.9)')
}
.width('100%')
.alignItems(HorizontalAlign.Center)
.padding({ top: 20, bottom: 20 })
// 详细信息
Row({ space: 0 }) {
Column({ space: 4 }) {
Text('💧')
.fontSize(18)
Text(`${weather.humidity}%`)
.fontSize(14)
.fontColor(Color.White)
Text('湿度', { fontSize: 11, fontColor: 'rgba(255,255,255,0.7)' })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column({ space: 4 }) {
Text('🌬️')
.fontSize(18)
Text(weather.windLevel)
.fontSize(14)
.fontColor(Color.White)
Text(weather.windDir, { fontSize: 11, fontColor: 'rgba(255,255,255,0.7)' })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column({ space: 4 }) {
Text('🌅')
.fontSize(18)
Text(weather.sunrise)
.fontSize(14)
.fontColor(Color.White)
Text('日出', { fontSize: 11, fontColor: 'rgba(255,255,255,0.7)' })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
Column({ space: 4 }) {
Text('🌇')
.fontSize(18)
Text(weather.sunset)
.fontSize(14)
.fontColor(Color.White)
Text('日落', { fontSize: 11, fontColor: 'rgba(255,255,255,0.7)' })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(16)
.backdropBlur(20)
// 空气质量
Row({ space: 12 }) {
Text('🌬️')
.fontSize(24)
Column({ space: 4 }) {
Text(`空气质量 ${weather.aqi} ${weather.aqiLevel}`)
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
Text('空气不错,可以正常户外活动')
.fontSize(12)
.fontColor('rgba(255,255,255,0.8)')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Text(weather.aqiLevel)
.fontSize(14)
.fontColor(Color.White)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.backgroundColor(this.getAqiColor(weather.aqi))
.borderRadius(20)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(16)
.backdropBlur(20)
// 24小时预报
Column({ space: 12 }) {
Text('24小时预报')
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
.width('100%')
Scroll(Axis.Horizontal) {
Row({ space: 4 }) {
ForEach(weather.hourly, (h: HourlyForecast) => {
this.HourlyItem(h)
})
}
}
.scrollBar(BarState.Off)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(16)
.backdropBlur(20)
// 7天预报
Column({ space: 8 }) {
Text('7天预报')
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
.width('100%')
ForEach(weather.daily, (d: DailyForecast) => {
this.DailyItem(d)
Divider().color('rgba(255,255,255,0.1)')
})
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(16)
.backdropBlur(20)
// 生活指数
Column({ space: 12 }) {
Text('生活指数')
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
.width('100%')
Grid() {
ForEach(weather.lifeIndex, (i: LifeIndex) => {
GridItem() { this.LifeIndexItem(i) }
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.width('100%')
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.15)')
.borderRadius(16)
.backdropBlur(20)
}
.width('100%')
.padding({ left: 20, right: 20, bottom: 40 })
}
.layoutWeight(1)
.scrollBar(BarState.Off)
}
.width('100%')
.height('100%')
// 城市选择弹窗
if (this.showCityList) {
Column() {
Blank()
Column({ space: 16 }) {
Row() {
Text('选择城市')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#1F2937')
Blank()
Text('✕')
.fontSize(20)
.onClick(() => this.showCityList = false)
}
.width('100%')
Row({ space: 8 }) {
TextInput({ text: this.searchCity, placeholder: '搜索城市' })
.layoutWeight(1)
.height(44)
.backgroundColor('#F3F4F6')
.onChange((v: string) => this.searchCity = v)
Button('添加')
.height(44)
.backgroundColor('#0EA5E9')
.onClick(() => this.addCity())
}
.width('100%')
Wrap({ space: 8 }) {
ForEach(this.cityList, (city: string, index: number) => {
Text(city)
.fontSize(14)
.fontColor(city === weather.city ? Color.White : '#374151')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.backgroundColor(city === weather.city ? '#0EA5E9' : '#F3F4F6')
.borderRadius(20)
.onClick(() => this.switchCity(index))
})
}
}
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius({ topLeft: 24, topRight: 24 })
}
.width('100%')
.height('100%')
.backgroundColor('rgba(0,0,0,0.5)')
.onClick(() => this.showCityList = false)
}
}
.width('100%')
.height('100%')
}
页面设计说明
主题色采用天蓝色渐变#0EA5E9→#7DD3FC,蓝色代表天空、清爽、科技,非常适合天气应用。使用毛玻璃backdropBlur效果,卡片半透明叠加在渐变背景上,视觉效果高级。所有文字白色,对比清晰。横向滚动的小时预报、网格布局的生活指数,交互流畅。
SDK配置
API 24,compatibleSdkVersion: “6.1.1(24)”
运行项目
将代码复制到 entry/src/main/ets/pages/Index.ets 即可运行。
项目总结
实现了天气展示、多城市管理、24小时/7天预报、空气质量、生活指数等功能。掌握了渐变色背景、毛玻璃效果、横向滚动列表、网格布局、底部弹窗等。后续可加入天气动画、天气预警通知、桌面天气小组件、降水提醒、逐分钟预报、台风路径、天气分享、深色模式等功能。
更多推荐



所有评论(0)