Flutter实战5 -- 天气查询APP重构之状态管理(ScopedModel)

栏目: IOS · Android · 发布时间: 5年前

内容简介:前面四篇文章:在第4篇文章中,为了方便管理状态,我们介绍了InheritedWidget,今天介绍ScopedModel,这是一个封装的InheritedWidget的库,使用起来更方便。ScopedModel:

前面四篇文章:

  1. Flutter实战1 --- 写一个天气查询的APP
  2. Flutter实战2 --- 写一个天气查询的APP
  3. FFlutter实战3 --- PC上运行Flutter APP
  4. 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使用,主要是下面三个类:

  1. Model

    你要继承 Model 这个类,实现自己的Models,这个Module类里,持有相关的数据,及实现一些业务逻辑,可以监听Model里的数据变化

  2. ScopedModel

    ScopedModel是一个Widget,确定Model的使用范围:像使用InheritedWidget一样,你需要用ScopedModel包其他Widget,而且Model也是包在ScopedModel里的,这样Model就可以沿着Widget树向下传递。

  3. ScopedModelDescendant ScopedModelDescendant也是一个Widget,在子Widget获取Model使用:使用ScopedModelDescendant,是为了在子Widget里找到相应的Model。只要是Model发生更改,它就会自动重建。

0x04 重构 -- 实现Model

新增了两个Model,分别是:

  1. 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();
  }
}
复制代码
  1. 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使用,所以重构如下:

  1. 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))
                                    );
                                  },
                              ),
                          );
                      }
                  );
        },
      )
    );
  }

}
复制代码
  1. 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
                                  ),
                                )
                              ],
                            );
                    },
                  ),
                )
              )
            ],
          )
        ],
      ),
    );
  }

}
复制代码

在使用 ScopedModelScopedModelDescendant 都使用到了泛型


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP+MySQL八大动态Web应用实战

PHP+MySQL八大动态Web应用实战

Jono Bacom / 吴连河、李剑 / 电子工业出版社 / 2008-6 / 68.00元

本书详细介绍了利用PHP+MySQL开发常见类型Web应用程序的完整设计和编码技术,并对整体设计与关键代码给予了细致、深入的剖析。其内容注重实践,提供了翔实完整的实战代码;思路独树一帜,突破过多描述语言细节的窠臼;行文风趣幽默,轻松调侃中将项目的完整设计过程分析得一清二楚。书中的示例项目完整而实用,读者甚至无需任何改动即可在实际中加以运用。. 本书适合对PHP/MySQL有初步了解但缺乏完整......一起来看看 《PHP+MySQL八大动态Web应用实战》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码