0x00 前言
前面四篇文章:
- Flutter实战1 — 写一个天气查询的APP
- Flutter实战2 — 写一个天气查询的APP
- FFlutter实战3 — PC上运行Flutter APP
- Flutter实战4 — 天气查询APP重构之状态管理(InheritedWidget)
在第4篇文章中,为了方便管理状态,我们介绍了InheritedWidget,今天介绍ScopedModel,这是一个封装的InheritedWidget的库,使用起来更方便。
0x01 代码
本篇文章所涉及的代码:
分支:scoped_model
0x02 ScopedModel
ScopedModel:github.com/brianegan/s…
可以方便的将model从父Widget传递到它的后代。而且还会在model更新时重建使用该model的所有子项。该库是从Fuchsia代码库中提取的。
0x03 ScopedModel引入
在pubspec.yaml
里加入:
scoped_model: ^1.0.1
然后运行flutter packages get
0x04 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发生更改,它就会自动重建。
0x05 重构 — 实现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();
}
}
0x06 重构 — 原有widget重构
Model实现完后,接下来就是对原有widget重构,
第一个步是添加ScopedModel,确定Model的使用范围:
ScopedModel<CityModel>(
model: CityModel(),
child: ...
);
第二步是使用ScopedModelDescendant,在子Widget获取Model使用,所以重构如下:
ScopedModelDescendant<CityModel>(
builder: (context,child,model){
//使用model
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实战5 — 天气查询APP重构之状态管理(ScopedModel)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22082.html