Flutter 实战:weather 天气应用的城市搜索、本地天气数据与鸿蒙适配解析
Flutter 实战weather 天气应用的城市搜索、本地天气数据与鸿蒙适配解析前言欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netweather是一个基于 Flutter 实现的本地天气演示应用。它内置了多个城市的天气数据支持通过搜索框过滤城市点击城市后切换当前天气卡片并展示温度、天气描述、湿度和风速以及对应的天气图标和颜色。本文基于项目真实源码展开重点分析本地天气数据结构、城市搜索过滤、当前城市切换、天气条件配色、主卡片布局、辅助指标展示和鸿蒙适配关注点。文章内容可直接发布到 CSDN不包含面向作者的检查说明。这个项目最重要的边界是它展示的是本地天气演示数据而不是联网天气服务。把边界写清楚技术文章才可靠。图示说明本文围绕 Flutter 天气应用的城市搜索、本地天气卡片、条件配色和跨端适配展开适合用于鸿蒙、Android、iOS 等多端应用开发复盘。一、项目定位与功能概览1.1 应用主题weather的定位是一个本地天气查询演示应用。用户可以在顶部搜索城市列表会实时过滤点击城市后页面中央会展示该城市的温度、天气状况、湿度和风速。核心功能如下功能页面表现源码实现搜索城市顶部搜索框_searchController、_searchCity()当前城市主天气卡片_selectedCity、_currentWeather温度展示大字号22°Cweather[temp]天气状态Sunny、Cloudy 等weather[condition]湿度展示Humidity 卡片weather[humidity]风速展示Wind 卡片weather[wind]其他城市下方列表_cities.where(...)城市切换点击列表项onTap1.2 默认数据项目启动后已经内置城市天气城市温度天气湿度风速New York22°CSunny6512 km/hLondon15°CCloudy808 km/hTokyo28°CClear556 km/hSydney18°CRainy9015 km/hParis20°CPartly Cloudy7010 km/hDubai38°CHot405 km/h1.3 学习价值这个项目适合学习以下 Flutter 实战能力如何用ListMapString, dynamic保存城市天气数据。如何通过搜索词过滤城市列表。如何点击列表项切换当前城市。如何按天气条件映射颜色和图标。如何在卡片中展示主天气和辅助指标。如何面向鸿蒙验证搜索、滚动和卡片布局。二、工程结构与运行方式2.1 工程结构项目保持标准 Flutter 工程结构核心代码集中在lib/main.dart文件或目录作用说明lib/main.dart应用入口与页面实现包含天气数据、搜索和列表逻辑pubspec.yaml依赖声明使用 Flutter SDK 与 Material 图标test/widget_test.dartWidget 测试入口可扩展为天气业务测试ohos/鸿蒙平台工程目录用于跨端构建和适配2.2 依赖声明项目没有引入复杂第三方依赖dependencies:flutter:sdk:fluttercupertino_icons:^1.0.8这说明天气展示、城市筛选和交互逻辑都由 Flutter 与 Dart 完成不依赖联网接口。2.3 常用命令开发和验证时可以使用以下命令flutter pub get flutter analyze fluttertestflutter run命令作用使用场景flutter pub get获取依赖首次运行或依赖变化flutter analyze静态分析检查语法和 lintflutter test执行测试验证 Widget 行为flutter run启动应用本地调试界面三、应用入口与主题配置3.1 main 函数应用入口保持 Flutter 标准写法voidmain(){runApp(constMyApp());}天气演示应用不需要启动时加载网络数据因此入口很简洁。3.2 MyApp 根组件根组件负责创建MaterialAppclassMyAppextendsStatelessWidget{constMyApp({super.key});overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:Weather,theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.lightBlue),),home:constMyHomePage(title:Weather),);}}这里有三个关键信息应用标题是Weather。主题种子色是Colors.lightBlue。首页是MyHomePage。3.3 主题色选择浅蓝色很适合天气类应用能和天空、空气、晴朗等视觉联想建立联系。当前源码没有显式设置useMaterial3: true因此文章以真实代码为准。如果后续需要统一 Material 3 表现可以在ThemeData中补充该配置。四、状态字段设计4.1 核心状态总览页面状态集中在_MyHomePageState中String_selectedCityNew York;String_searchQuery;bool _isLoadingfalse;finalListMapString,dynamic_cities[{name:New York,temp:22,condition:Sunny,humidity:65,wind:12,icon:Icons.wb_sunny},{name:London,temp:15,condition:Cloudy,humidity:80,wind:8,icon:Icons.cloud},];finalTextEditingController_searchControllerTextEditingController();4.2 字段说明字段类型初始值作用_selectedCityStringNew York当前选中城市_searchQueryString空字符串搜索过滤关键词_isLoadingboolfalse预留加载状态_citiesListMapString, dynamic6 个城市城市天气数据_searchControllerTextEditingController空搜索输入控制器4.3 状态分层状态类别字段说明当前展示_selectedCity主卡片显示哪座城市过滤状态_searchQuery列表过滤条件数据状态_cities城市天气集合输入状态_searchController搜索框文本4.4 预留字段_isLoading在当前源码中没有实际使用属于预留状态字段。它可能是为后续接入网络天气接口做准备但在现版本中没有参与 UI 逻辑。五、控制器生命周期管理5.1 搜索控制器顶部搜索框使用一个控制器finalTextEditingController_searchControllerTextEditingController();5.2 dispose 释放资源页面销毁时释放控制器overridevoiddispose(){_searchController.dispose();super.dispose();}5.3 生命周期表阶段行为页面创建创建搜索控制器用户输入控制器保存搜索词页面销毁释放控制器六、当前城市天气查询6.1 currentWeather getter当前城市天气通过_currentWeather获取MapString,dynamicget_currentWeather{return_cities.firstWhere((city)city[name]_selectedCity,orElse:()_cities[0],);}6.2 firstWhere 的作用firstWhere会按条件查找第一个匹配项。如果没有找到则回退到列表第一个城市。6.3 当前城市与天气卡片主卡片中的温度、天气状况、湿度和风速都来自_currentWeather。6.4 兜底策略情况行为找到选中城市显示该城市天气未找到选中城市回退到列表第一项七、搜索过滤逻辑7.1 searchCity 方法搜索词由_searchCity()更新void_searchCity(Stringquery){setState((){_searchQueryquery.toLowerCase();});}7.2 小写匹配这里把搜索词转成小写query.toLowerCase()这样能让搜索匹配不区分大小写。7.3 过滤条件城市列表展示时使用_cities.where((city)city[name]!_selectedCitycity[name].toLowerCase().contains(_searchQuery))7.4 过滤规则表条件结果名称等于当前城市不显示在 Other Cities名称包含搜索词显示名称不匹配搜索词不显示7.5 过滤体验用户输入搜索词后下方其他城市列表会实时缩小范围便于快速定位城市。八、天气条件配色8.1 getWeatherColor 方法天气颜色由_getWeatherColor()决定Color_getWeatherColor(Stringcondition){switch(condition.toLowerCase()){casesunny:caseclear:returnColors.orange;casecloudy:casepartly cloudy:returnColors.blueGrey;caserainy:returnColors.blue;casehot:returnColors.red;default:returnColors.lightBlue;}}8.2 条件映射表天气条件颜色Sunny / ClearorangeCloudy / Partly CloudyblueGreyRainyblueHotred其他lightBlue8.3 颜色使用位置天气颜色会用于主卡片背景淡色。主温度大字号。当前天气描述文本。城市列表图标颜色。8.4 视觉价值颜色让用户不必读完文字也能快速感知天气类型比如橙色表示晴朗蓝色表示雨天红色表示高温。九、天气图标映射9.1 图标数据每个城市数据里都预置了图标{name:New York,temp:22,condition:Sunny,humidity:65,wind:12,icon:Icons.wb_sunny}9.2 图标使用方式主天气卡片和列表项都会使用城市图标Icon(weather[icon],size:80,color:weatherColor)leading:Icon(city[icon],color:_getWeatherColor(city[condition]))9.3 图标语义图标含义wb_sunny晴天cloud多云grain雨天cloud_queue局部多云wb_sunnyHot高温晴热9.4 图标与颜色协同图标和颜色一起构成天气语义减少用户理解成本。十、主天气卡片布局10.1 主卡片结构主天气信息放在一张大卡片里Card(color:weatherColor.withAlpha(30),child:Padding(padding:constEdgeInsets.all(32),child:Column(...),),)10.2 城市标题标题区域展示地点图标和城市名Row(mainAxisAlignment:MainAxisAlignment.center,children:[constIcon(Icons.location_on,size:20),constSizedBox(width:4),Text(_selectedCity),],)10.3 温度展示温度使用超大字号Text(${weather[temp]}°C,style:TextStyle(fontSize:72,fontWeight:FontWeight.bold,color:weatherColor),)10.4 状态文本天气描述文本如下Text(weather[condition])10.5 卡片作用元素作用城市名当前查看对象温度当前核心数据天气描述当前天气状态图标和颜色增强视觉识别十一、湿度与风速卡片11.1 双卡片布局湿度和风速使用一行双卡片Row(children:[Expanded(child:Card(...)),constSizedBox(width:8),Expanded(child:Card(...)),],)11.2 湿度卡片Text(${weather[humidity]}%)11.3 风速卡片Text(${weather[wind]} km/h)11.4 指标对比表指标单位作用温度°C主天气感知湿度%体感辅助风速km/h风感辅助十二、其他城市列表12.1 Other Cities 标题页面下方列表标题为constText(Other Cities)12.2 列表生成其他城市列表通过过滤后的映射生成..._cities.where(...).map((city){returnCard(child:ListTile(...),);})12.3 列表内容每个列表项展示左侧天气图标。中间城市名和天气描述。右侧温度。12.4 当前城市排除列表过滤时会排除当前选中的城市因此当前查看城市只在主卡片展示不会重复出现在下方列表。十三、点击城市切换13.1 切换逻辑点击列表项时会更新当前城市onTap:(){setState((){_selectedCitycity[name];_searchController.clear();_searchCity();});}13.2 切换后清空搜索切换城市后会清空搜索框并重置搜索词避免列表继续停留在旧筛选状态。13.3 交互闭环点击城市 - 更新 selectedCity - 清空搜索框 - 重置 searchQuery - 主天气卡片刷新 - 其他城市列表刷新13.4 体验说明这个设计让用户可以先搜索城市再点选城市随后界面回到完整列表状态。十四、鸿蒙适配关注点14.1 为什么适配风险较低weather主要由 Flutter 标准组件和 Dart 状态逻辑构成不依赖网络、定位、数据库、系统天气接口或平台通道因此基础适配风险较低。模块是否依赖平台能力适配关注度搜索输入Flutter 标准输入中城市列表Flutter 标准列表低天气卡片Flutter 标准卡片低图标与颜色Flutter 标准图标低网络天气当前未实现高14.2 输入法与软键盘鸿蒙设备上需要重点验证搜索框是否正常弹出键盘。输入后列表是否实时过滤。清空按钮是否正常工作。键盘弹出后主卡片是否被遮挡。14.3 列表滚动底部Other Cities使用列表展示城市数量增加时要观察滚动是否顺滑长城市名是否溢出。14.4 数据边界当前项目只是本地天气演示所有城市数据都写在_cities中并不是联网实时天气。如果要做正式天气应用需要接入真实天气 API。当前项目更适合作为 Flutter 天气 UI 和搜索过滤样例不应理解为完整的实时天气服务。十五、测试设计与默认测试改造15.1 当前测试入口项目中的测试文件仍是默认计数器测试。对于天气应用更有价值的是验证初始城市、搜索过滤、城市切换和卡片渲染。15.2 初始页面测试testWidgets(weather app renders initial state,(WidgetTestertester)async{awaittester.pumpWidget(constMyApp());expect(find.text(Weather),findsWidgets);expect(find.text(New York),findsOneWidget);expect(find.text(Humidity),findsOneWidget);expect(find.text(Wind),findsOneWidget);});15.3 搜索框测试testWidgets(can type into search box,(WidgetTestertester)async{awaittester.pumpWidget(constMyApp());awaittester.enterText(find.byType(TextField),Tokyo);awaittester.pump();expect(find.text(Tokyo),findsWidgets);});15.4 城市切换测试testWidgets(can select a city from list,(WidgetTestertester)async{awaittester.pumpWidget(constMyApp());awaittester.tap(find.text(London));awaittester.pump();expect(find.text(London),findsWidgets);});15.5 天气颜色测试建议如果把_getWeatherColor()抽成纯函数可以直接测试不同条件下的颜色映射。十六、可维护性优化方向16.1 抽离天气模型当前使用 Map 保存城市天气简洁但类型不够明确。可以抽成模型classWeatherCity{constWeatherCity({requiredthis.name,requiredthis.temp,requiredthis.condition,requiredthis.humidity,requiredthis.wind,requiredthis.icon,});finalStringname;finalint temp;finalStringcondition;finalint humidity;finalint wind;finalIconDataicon;}16.2 增加真实接口如果后续接入网络天气 API可以把_cities替换为接口返回的数据并将_isLoading用于加载态。16.3 支持收藏城市可以加入收藏城市、置顶城市或常看城市让天气工具更实用。16.4 支持刷新当前项目没有手动刷新按钮。若接入实时天气数据可以增加下拉刷新或顶部刷新按钮。十七、功能扩展方向17.1 增加真实天气接口接入 OpenWeather、WeatherAPI 或其他天气服务后就可以把本地演示升级为实时天气工具。17.2 增加小时预报在主卡片下方展示未来几个小时的温度变化会更接近正式天气应用。17.3 增加每日预报可以扩展为 5 天或 7 天预报让页面更完整。17.4 增加位置定位后续可以加入定位能力自动显示用户当前城市。十八、常见问题与优化建议18.1 为什么搜索框是本地过滤因为源码中没有网络请求。搜索只是通过字符串匹配过滤_cities。18.2 为什么城市列表会排除当前城市这样当前城市只在主卡片显示避免重复。18.3 为什么天气颜色不是统一色不同天气条件需要不同视觉语义颜色能帮助用户快速理解天气类型。18.4 为什么没有加载动画源码中虽然有_isLoading字段但当前没有接入联网数据所以没有真正使用加载态。18.5 鸿蒙适配最应该关注什么重点关注搜索输入、列表滚动、卡片排版、长城市名显示和软键盘遮挡。当前项目没有联网能力也没有实时天气刷新。十九、完整流程复盘19.1 页面启动流程main() - runApp(MyApp) - MaterialApp - MyHomePage - 初始化城市列表 - build 渲染主卡片和列表19.2 搜索流程输入城市名 - _searchCity - 小写关键词更新 - 过滤 Other Cities - 页面刷新19.3 城市切换流程点击列表项 - 更新 selectedCity - 清空搜索 - 重置搜索词 - 主卡片刷新19.4 视觉计算流程读取当前城市天气 - 计算颜色 - 计算图标 - 显示温度、天气、湿度和风速二十、相关资源与继续学习20.1 Flutter 学习资源天气应用涉及输入、列表、卡片和测试可以结合以下资源学习资源内容Flutter DocsFlutter 官方开发文档Dart 官方文档Dart 语言与核心库Widget catalogFlutter 常用组件Flutter testingWidget 测试与交互模拟20.2 天气应用扩展方向后续可以继续增强真实天气接口。用户定位。小时预报。未来几天预报。收藏城市。刷新按钮。深色模式。单位切换。20.3 跨端实践价值weather很适合作为 Flutter 适配鸿蒙的小型天气样例。它依赖很轻但覆盖了搜索输入、列表过滤、卡片展示、图标颜色映射和滚动布局能帮助开发者验证很多跨端基础能力。总结weather用简洁的 Flutter 代码实现了一个本地天气演示应用。它通过_cities保存城市天气数据通过_selectedCity控制当前展示城市通过_searchQuery实现搜索过滤通过_getWeatherColor()和城市数据中的icon字段提供天气语义化展示并在列表中支持切换城市。从工程角度看这个项目最值得学习的是“本地天气数据 搜索过滤 主卡片展示”的组合方式。面向鸿蒙适配时项目依赖较轻主要需要验证搜索输入、列表滚动、卡片布局和触摸反馈。对于想学习 Flutter 天气类 UI 的开发者来说它是一个清晰、实用且容易扩展的案例。如果这篇文章对你有帮助欢迎点赞、收藏、关注你的支持是我持续创作的动力相关资源Flutter 官方文档OpenHarmony 官网OpenHarmony CrossPlatform 社区

相关新闻