flutter天气_Flutter 入门指北系列最终之实战篇

本文是Flutter入门指北系列的最终篇,介绍如何使用Fluro进行路由管理,结合dio和rxdart实现BLoC状态管理,用Fluent设计系统打造一个天气应用。涵盖了导入插件、数据库管理、各页面的编写,包括首页、城市选择、天气详情和设置页的全局主题切换。
摘要由CSDN通过智能技术生成
95d5832403923cb2eb5af8be92fb38eb.gif

码个蛋(codeegg)第 696 次推文

作者:Kuky_xs

博客:https://www.jianshu.com/p/97c2dbcac3af

还记得Flutter系列不?上一次讲到网络的,想不起来的回顾一下~

Flutter入门指北(Part 13)之网络

今天分析Flutter入门指北系列的最终篇啦~

讲完了常用的部件和网络请求后,差不多该进入整体实战了,这里我们将写一个比较熟悉的项目,郭神的 cool weather。项目将使用 fluro 实现路由管理,dio 实现网络请求,rxdart 实现 BLoC 进行状态管理和逻辑分离,使用文件,shared_preferences,sqflite 实现本地的数据持久化。这边先给出项目的地址:flutter_weather,以及最后实现的效果图:

3554eb82ceedb81cfe7dfbb6eb8224aa.png e69cc678663eab93aa1ab43d68958e43.gif 8c28e47fc643db890d84796a03f73b1f.gif

除了 fluro 别的基本上前面都讲了,所以在开始正式的实战前,先讲下 fluro

Fluro

fluro 是对 Navigator 的一个封装,方便更好的管理路由跳转,当然还存在一些缺陷,例如目前只支持传递字符串,不能传递中文等,但是这些问题都算不上是大问题。

fluro 的使用很简单,大概分如下的步骤:

1. 在全局定义一个 Router实例

final router = Router;

2. 使用 Router实例定义路径和其对应的Handler对象

// 例如定义一个 CityPage 的路径和 Handler
Handler cityHandler = Handler(handlerFunc: (_, params) {
// 传递的参数都在 params 中,params 是一个 Map> 类型参数
String cityId = params['city_id']?.first;
return BlocProvider(child: WeatherPage(city: cityId), bloc: WeatherBloc);
});
// 定义路由的路径和参数
// 需要注意的是,第一个页面的路径必须为 "/",别的可为 "/" + 任意拼接
router.define('/city', handler: cityHandler);
// 或者官方提供的另一种方式
router.define('/city/:city_id', handler: cityHandler);

3. 将router注册到MaterialApp的 onGenerateRoute 中

MaterialApp(onGenerateRoute: router);

4. 最后通过 Router 实例进行跳转,如果有参数传递则会在新的页面收到

router.navigateTo(context, '/city?city_id=CN13579');
// 或者官方的方式
router.navigateTo(context, '/city/CN13579');

在 fluro 中提供了多种路由动画,包括 fadeIn,inFromRight 等。讲完了使用,就进入实战了。

flutter_weather 实战

导入插件

在开始的时候,已经提到了整体功能的实现需求,所以这边需要导入的插件以及存放图片的文件夹如下:

dependencies:
flutter:
sdk: flutter

cupertino_icons: ^0.1.2
fluro: ^1.4.0
dio: ^2.1.0
shared_preferences: ^0.5.1+2
sqflite: ^1.1.3
fluttertoast: ^3.0.3
rxdart: ^0.21.0
path_provider: 0.5.0+1

dev_dependencies:
flutter_test:
sdk: flutter

flutter:
uses-material-design: true

assets:
- images/
顶层静态实例的实现

有许多实例需要在顶层注册,然后在全局使用,包括但不限于 fluro 的 router,http,database 等等。在这个项目中,需要用到的就是这三个实例,会在全局调用,所以在开始前进行初始化,当然 http 和 database 在使用的时候创建也可以,完全看个人习惯,但是 fluro 的管理类必须在一开始就注册完成。首先需要定义一个 Application类用来存放这些静态实例

class Application {
   
static HttpUtils http; // 全局网络
static Router router; // 全局路由
static DatabaseUtils db; // 全局数据库
}

接着就是对相应方法类的编写,其中 HttpUtil和 DatabaseUtils在前面有讲过,这边不重复讲,会讲下数据库如何建立。

Fluro 路由管理类

首先,需要知道,该项目的界面大概分如下的界面(当然可先只定义首页,剩下用到了再定义,该项目相对简单,所以先列出来):省选择页,市选择页,区选择页,天气展示页,设置页。所以 fluro 的管理类可按如下定义:

// 查看 `routers/routers.dart` 文件
class Routers {
/// 各个页面对应的路径
static const root = '/';
static const weather = '/weather';
static const provinces = '/provinces';
static const cities = '/cities';
static const districts = '/districts';
static const settings = '/settings';

/// 该方法用于放到 `main` 方法中定义所有的路由,
/// 对应的 handler 可放同一个文件,也可放另一个文件,看个人喜好
static configureRouters(Router router) {
router.notFoundHandler = notFoundHandler;

router.define(root, handler: rootHandler); // 首页

router.define(weather, handler: weatherHandler); // 天气展示页

router.define(provinces, handler: provincesHandler); // 省列表页

router.define(cities, handler: citiesHandler); // 省下市列表页

router.define(districts, handler: districtsHandler); // 市下区列表页

router.define(settings, handler: settingsHandler); // 设置页
}

/// 生成天气显示页面路径,需要用到城市 id
static generateWeatherRouterPath(String cityId) => '$weather?city_id=$cityId';

/// 生成省下的市列表页相应路径 需要用到省 id 及省名
static generateProvinceRouterPath(int provinceId, String name)
=> '$cities?province_id=$provinceId&name=$name';

/// 生成市下的区列表页相应路径,需用到市 id 及市名
static generateCityRouterPath(int provinceId, int cityId, String name)
=> '$districts?province_id=$provinceId&city_id=$cityId&name=$name';
}
/// 查看 `routers/handler.dart` 文件
Handler notFoundHandler = Handler(handlerFunc: (_, params) {
Logger('RouterHandler:').log('Not Found Router'); // 当找不到相应的路由时,打印信息处理
});

Handler rootHandler = Handler(handlerFunc: (_, params) => SplashPage);

Handler weatherHandler = Handler(handlerFunc: (_, params) {
String cityId = params['city_id']?.first; // 获取相应的参数
return WeatherPage(city: cityId);
});

Handler provincesHandler = Handler(handlerFunc: (_, params) => ProvinceListPage);

Handler citiesHandler = Handler(handlerFunc: (_, params) {
String provinceId = params['province_id']?.first;
String name = params['name']?.first;
return CityListPage(provinceId: provinceId,
name: FluroConvertUtils.fluroCnParamsDecode(name));
});

Handler districtsHandler = Handler(handlerFunc: (_, params) {
String provinceId = params['province_id']?.first;
String cityId = params['city_id']?.first;
String name = params['name']?.first;
return DistrictListPage(provinceId: provinceId, cityId: cityId,
name: FluroConvertUtils.fluroCnParamsDecode(name));
});

Handler settingsHandler = Handler(handlerFunc: (_, params) => SettingsPage);

那么界面的路由到这就编写好了,但是前面提到了 fluro 目前不支持中文的传递,所以在传递中文时候,需要先进行转码,这边提供一个自己写的方法,小伙伴有更好的方法也可以直接在项目提 issue

/// 查看 `utils/fluro_convert_util.dart` 文件
class FluroConvertUtils {
/// fluro 传递中文参数前,先转换,fluro 不支持中文传递
static String fluroCnParamsEncode(String originalCn) {
StringBuffer sb = StringBuffer;
var encoded = Utf8Encoder.convert(originalCn); // utf8 编码,会生成一个 int 列表
encoded.forEach((val) => sb.write('$val,')); // 将 int 列表重新转换成字符串
return sb.toString.substring(0, sb.length - 1).toString;
}

/// fluro 传递后取出参数,解析
static String fluroCnParamsDecode(String encodedCn) {
var decoded = encodedCn.split('[').last.split(']&#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值