内容简介:前面四篇文章:在第4篇文章中,为了方便管理状态,我们介绍了InheritedWidget,今天介绍ScopedModel,这是一个封装的InheritedWidget的库,使用起来更方便。ScopedModel:
前面四篇文章:
- Flutter实战1 --- 写一个天气查询的APP
- Flutter实战2 --- 写一个天气查询的APP
- FFlutter实战3 --- PC上运行Flutter APP
- Flutter实战4 -- 天气查询APP重构之状态管理(InheritedWidget)
在第4篇文章中,为了方便管理状态,我们介绍了InheritedWidget,今天介绍ScopedModel,这是一个封装的InheritedWidget的库,使用起来更方便。
0x01 ScopedModel
ScopedModel: github.com/brianegan/s…
可以方便的将model从父Widget传递到它的后代。而且还会在model更新时重建使用该model的所有子项。该库是从Fuchsia代码库中提取的。
0x02 ScopedModel引入
在 pubspec.yaml
里加入:
scoped_model: ^1.0.1 复制代码
然后运行 flutter packages get
0x03 ScopedModel使用
ScopedModel使用,主要是下面三个类:
-
Model
你要继承
Model
这个类,实现自己的Models,这个Module类里,持有相关的数据,及实现一些业务逻辑,可以监听Model里的数据变化 -
ScopedModel
ScopedModel是一个Widget,确定Model的使用范围:像使用InheritedWidget一样,你需要用ScopedModel包其他Widget,而且Model也是包在ScopedModel里的,这样Model就可以沿着Widget树向下传递。
-
ScopedModelDescendant ScopedModelDescendant也是一个Widget,在子Widget获取Model使用:使用ScopedModelDescendant,是为了在子Widget里找到相应的Model。只要是Model发生更改,它就会自动重建。
0x04 重构 -- 实现Model
新增了两个Model,分别是:
- CityModel
作用:获取城市列表
import 'dart:convert'; import 'package:flutter/widgets.dart'; import 'package:gdg_weather/page/city/CityData.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:http/http.dart' as http; class CityModel extends Model{ List<CityData> cityList = new List<CityData>(); CityModel(){ } static CityModel of(BuildContext context) => ScopedModel.of<CityModel>(context,rebuildOnChange: true); //获取城市列表的方法 void getCityList() async { final response = await http.get('https://search.heweather.net/top?group=cn&key=ebb698e9bb6844199e6fd23cbb9a77c5'); List<CityData> list = new List<CityData>(); if(response.statusCode == 200){ //解析数据 Map<String,dynamic> result = json.decode(response.body); for(dynamic data in result['HeWeather6'][0]['basic']){ CityData cityData = CityData(data['location']); list.add(cityData); } } cityList = list; //这里一定要,数据变化,通知widget刷新 notifyListeners(); } } 复制代码
- WeatherModel
import 'dart:convert'; import 'package:gdg_weather/page/weather/WeatherData.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:http/http.dart' as http; class WeatherModel extends Model{ WeatherData weather = WeatherData.empty(); void fetchWeather(String cityName) async{ final response = await http.get('https://free-api.heweather.com/s6/weather/now?location='+cityName+'&key=ebb698e9bb6844199e6fd23cbb9a77c5'); if(response.statusCode == 200){ weather = WeatherData.fromJson(json.decode(response.body)); }else{ weather = WeatherData.empty(); } notifyListeners(); } } 复制代码
0x05 重构 -- 原有widget重构
Model实现完后,接下来就是对原有widget重构,第一个步是添加ScopedModel,确定Model的使用范围,第二部使用ScopedModelDescendant,在子Widget获取Model使用,所以重构如下:
- CityWidget
class CityState extends State<CityWidget>{ CityState(){ } @override Widget build(BuildContext context) { // TODO: implement build return ScopedModel<CityModel>( model: CityModel(), child: ScopedModelDescendant<CityModel>( builder: (context,child,model){ model.getCityList(); return ListView.builder( itemCount: model.cityList.length, itemBuilder: (context,index){ return ListTile( title: GestureDetector( child: Text(model.cityList[index].cityName), onTap:(){ Navigator.push( context, MaterialPageRoute(builder: (context) => WeatherWidget(model.cityList[index].cityName)) ); }, ), ); } ); }, ) ); } } 复制代码
- WeatherWidget
class WeatherState extends State<WeatherWidget>{ String cityName; WeatherState(String cityName){ this.cityName = cityName; } @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( body: Stack( fit: StackFit.expand, children: <Widget>[ Image.asset("images/weather_bg.jpg",fit: BoxFit.fitHeight,), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( width: double.infinity, margin: EdgeInsets.only(top: 40.0), child: new Text( this.cityName, textAlign: TextAlign.center, style: new TextStyle( color: Colors.white, fontSize: 30.0, ), ), ), Container( width: double.infinity, margin: EdgeInsets.only(top: 100.0), child: ScopedModel<WeatherModel>( model: WeatherModel(), child: ScopedModelDescendant<WeatherModel>( builder: (context,child,model){ model.fetchWeather(this.cityName); return Column( children: <Widget>[ Text( model.weather?.tmp, style: new TextStyle( color: Colors.white, fontSize: 80.0 ) ), Text( model.weather?.cond, style: new TextStyle( color: Colors.white, fontSize: 45.0 ) ), Text( model.weather?.hum, style: new TextStyle( color: Colors.white, fontSize: 30.0 ), ) ], ); }, ), ) ) ], ) ], ), ); } } 复制代码
在使用 ScopedModel
和 ScopedModelDescendant
都使用到了泛型
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Flutter实战4 -- 天气查询APP重构之状态管理(InheritedWidget)
- Flutter实战1 --- 写一个天气查询的APP
- Flutter实战2 --- 写一个天气查询的APP
- Python学习笔记(六)——查询天气脚本
- Airbnb 的前端重构
- 重构推送服务
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP+MySQL八大动态Web应用实战
Jono Bacom / 吴连河、李剑 / 电子工业出版社 / 2008-6 / 68.00元
本书详细介绍了利用PHP+MySQL开发常见类型Web应用程序的完整设计和编码技术,并对整体设计与关键代码给予了细致、深入的剖析。其内容注重实践,提供了翔实完整的实战代码;思路独树一帜,突破过多描述语言细节的窠臼;行文风趣幽默,轻松调侃中将项目的完整设计过程分析得一清二楚。书中的示例项目完整而实用,读者甚至无需任何改动即可在实际中加以运用。. 本书适合对PHP/MySQL有初步了解但缺乏完整......一起来看看 《PHP+MySQL八大动态Web应用实战》 这本书的介绍吧!