前面四篇文章:git
在第4篇文章中,为了方便管理状态,咱们介绍了InheritedWidget,今天介绍ScopedModel,这是一个封装的InheritedWidget的库,使用起来更方便。github
本篇文章所涉及的代码:json
分支:scoped_modelbash
ScopedModel:github.com/brianegan/s…async
能够方便的将model从父Widget传递到它的后代。并且还会在model更新时重建使用该model的全部子项。该库是从Fuchsia代码库中提取的。ide
在pubspec.yaml
里加入:post
scoped_model: ^1.0.1
复制代码
而后运行flutter packages get
fetch
ScopedModel使用,主要是下面三个类:ui
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发生更改,它就会自动重建。
新增了两个Model,分别是:
做用:获取城市列表
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();
}
}
复制代码
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();
}
}
复制代码
Model实现完后,接下来就是对原有widget重构,
第一个步是添加ScopedModel,肯定Model的使用范围:
ScopedModel<CityModel>(
model: CityModel(),
child: ...
);
复制代码
第二步是使用ScopedModelDescendant,在子Widget获取Model使用,因此重构以下:
ScopedModelDescendant<CityModel>(
builder: (context,child,model){
//使用model
model....
}
)
复制代码
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))
);
},
),
);
}
);
},
)
);
}
}
复制代码
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
都使用到了泛型