目录
- Dart语言下的Flutter
- Flutter Widget
- Flutter 布局
- Flutter 页面
- 路由跳转
- 网络请求
- Json序列号
- Redux
一、Dart语言下的Flutter
这里详细的不做详解,只简单讲述下 Dart 的一些特性,主要涉及的是 Flutter下使用。
1.1、基本类型
- var 可以定义变量,如
var tag = "666
,这和 Swift、JS 、 Kotlin 等语言类似,同时支持闭包。
-
Dart
属于是强类型语言 ,但可以用var
来声明变量,Dart
会自推导出数据类型,所以 var 实际上是编译期的“语法糖”。dynamic
表示动态类型, 被编译后,实际是一个 object 类型,在编译期间不进行任何的类型检查,而是在运行期进行类型检查。 -
Dart 中 number 类型分为
int
和double
,Dart 中没有float
类型。
- Dart 下只有
bool
型可以用于 if 等判断 。
- Dart 中,switch 支持 String 类型
类型对照表
Dart | Android | ios |
---|---|---|
null | null | nil |
bool | java.lang.Boolean | Bool |
int | java.lang.Integer | Int、Int64等 |
List | java.util.ArrayList | Array |
Map | java.util.HashMap | Dictionary |
1.2、变量
- Dart 不需要给变量设置
setter
、getter
方法,Dart 中所有的基础类型、类等都继承 Object ,默认值是 NULL, 自带 getter 和 setter ,而如果是final
或者const
的话,那么它只有一个 getter 方法。
- Dart 中 final 和 const 表示常量,比如
final name = 'GSY'; const value= 1000000;
同时 static const 组合代表了静态常量,其中 const 的值在编译期确定,final 的值要到运行时才确定。
- Dart 下的数值,在作为字符串使用时,是需要
显式指定
的。比如:int i = 0; print("aaaa" + i); 这样并不支持,需要 print("aaaa" + i.toString()); 这样使用,这和 Java 与 JS 存在差异,所以在使用动态类型时,需要注意不要把 number 类型当做 String 使用。
- Dart 中数组等于列表,所以
var list = []; 和 List list = new List()
可以简单看做一样。
1.3、方法
- Dart 下
??
属于操作符,如:AA ?? "999"
表示如果 AA 为空,返回999;AA ??= "999"
表示如果 AA 为空,给 AA 设置成 999。
- Dart 方法可以设置 参数默认值 和 指定名称 。比如:
getDetail(Sting userName, reposName, {branch = "master"}){}
方法,这里 branch 不设置的话,默认是 “master” 。参数类型 可以指定或者不指定。调用效果:getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");
- Dart 不像 Java ,没有关键词
public
、private
等修饰符,==_==下横向直接代表 private 。
- Dart 中
多构造函数
,可以通过如下代码实现的。默认构造方法只能有一个,而通过Model.empty() 方法可以创建一个空参数的类,而变量初始化值时,只需要通过 this.name 在构造方法中指定即可:
class ModelA {
String name;
String tag;
//默认构造方法,赋值给name和tag
ModelA(this.name, this.tag);
//返回一个空的ModelA
ModelA.empty();
//返回一个设置了name的ModelA
ModelA.forName(this.name);
}
1.4、Flutter
Flutter 中支持
async/await
,如下代码所示, async/await 其实只是语法糖,最终会编译为 Flutter 中返回 Future 对象,之后通过 then 可以执行下一步。如果返回的还是 Future 便可以then().then.()
的流式操作了 。
///模拟等待两秒,返回OK
request() async {
await Future.delayed(Duration(seconds: 1));
return "ok!";
}
///得到"ok!"后,将"ok!"修改为"ok from request"
doSomeThing() async {
String data = await request();
data = "ok from request";
return data;
}
///打印结果
renderSome() {
doSomeThing().then((value) {
print(value);
///输出ok from request
});
}
- Flutter 中
setState
很有 React Native 的既视感,Flutter 中也是通过 State 跨帧实现管理数据状态的,这个后面会详细讲到。
- Flutter 中一切皆 Widget 呈现,通过
build
方法返回 Widget,这也是和 React Native 中,通过render
函数返回需要渲染的 component 一样的模式。
二、Flutter Widget
-
在
Flutter 中一切皆 Widget
,Widget 是一切的基础,利用响应式模式进行渲染。 -
我们可以通过修改数据,再用
setState
设置数据,Flutter 会自动通过绑定的数据更新 Widget , 所以你需要做的就是实现 Widget 界面,并且和数据绑定起来。 -
Widget 分为
有状态
和无状态
两种,在 Flutter 中每个页面都是一帧,无状态就是保持在那一帧,而有状态的 Widget 当数据更新时,其实是创建了新的 Widget,只是 State 实现了跨帧的数据同步保存。
这里有个小 Tip ,当代码框里输入
stl
的时候,可以自动弹出创建无状态控件的模板选项,而输入 stf 的时,就会弹出创建有状态 Widget 的模板选项。
3.1 无状态StatelessWidget
直接进入主题,如下下代码所示是无状态 Widget 的简单实现。继承 StatelessWidget,通过
build
方法返回一个布局好的控件。
Widget 和 Widget 之间通过
child:
进行嵌套。其中有的 Widget 只能有一个 child,比如下方的Container
;有的 Widget 可以多个 child ,也就是children
,比如Column` 布局,下方代码便是 Container Widget 嵌套了 Text Widget。
import 'package:flutter/material.dart';
class DemoWidget extends StatelessWidget {
final String text;
//数据可以通过构造方法传递进来
DEMOWidget(this.text);
@override
Widget build(BuildContext context) {
//这里返回你需要的控件
//这里末尾有没有的逗号,对于格式化代码而已是不一样的。
return Container(
//白色背景
color: Colors.white,
//Dart语法中,?? 表示如果text为空,就返回尾号后的内容。
child: Text(text ?? "这就是无状态DMEO"),
);
}
}
3.2 有状态StatefulWidget
如下代码,是有状态的widget的简单实现,你需要创建管理的是主要是 State
, 通过 State 的 build
方法去构建控件。在 State 中,你可以动态改变数据,在 setState
之后,改变的数据会触发 Widget 重新构建刷新,而下方代码中,是通过延两秒之后,让文本显示为 "这就变了数值"。
import 'dart:async';
import 'package:flutter/material.dart';
class DemoStateWidget extends StatefulWidget {
final String text;
////通过构造方法传值
DemoStateWidget(this.text);
///主要是负责创建state
@override
_DemoStateWidgetState createState() => _DemoStateWidgetState(text);
}
class _DemoStateWidgetState extends State<DemoStateWidget> {
String text;
_DemoStateWidgetState(this.text);
@override
void initState() {
///初始化,这个函数在生命周期中只调用一次
super.initState();
///定时1秒
new Future.delayed(const Duration(seconds: 1), () {
setState(() {
text = "这就变了数值";
});
});
}
@override
void dispose() {
///销毁
super.dispose();
}
@override
void didChangeDependencies() {
///在initState之后调 Called when a dependency of this [State] object changes.
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return Container(
child: Text(text ?? "这就是有状态DMEO"),
);
}
}
三、Flutter布局
Flutter 中拥有需要将近30种内置的
布局Widget
,其中常用有 Container、Padding、Center、Flex、Stack、Row、Column、ListView 等,下面简单讲解它们的特性和使用,大家了解知道有这些即可,使用时候具体属性可以再查。
-
Container
:最常用的默认控件,但是实际上它是由多个内置控件组成的模版,只能包含一个child,支持 padding,margin,color,宽高,decoration(一般配置边框和阴影)等配置,在 Flutter 中,不是所有的控件都有 宽高、padding、margin、color 等属性,所以才会有 Padding、Center 等 Widget 的存在。
///四周10大小的maring
margin: EdgeInsets.all(10.0),
height: 120.0,
width: 500.0,
///透明黑色遮罩
decoration: new BoxDecoration(
///弧度为4.0
borderRadius: BorderRadius.all(Radius.circular(4.0)),
///设置了decoration的color,就不能设置Container的color。
color: Colors.black,
///边框
border: new Border.all(color: Color(GSYColors.subTextColor), width: 0.3)),
child:new Text("666666"));
-
Column
、Row
绝对是必备布局, 横竖布局也是日常中最常见的场景。如下方所示,它们常用的有这些属性配置:主轴方向是 start 或 center 等;副轴方向方向是 start 或 center 等;mainAxisSize 是充满最大尺寸,或者只根据子 Widget 显示最小尺寸。
//主轴方向,Column的竖向、Row我的横向
mainAxisAlignment: MainAxisAlignment.start,
//默认是最大充满、还是根据child显示最小大小
mainAxisSize: MainAxisSize.max,
//副轴方向,Column的横向、Row我的竖向
crossAxisAlignment :CrossAxisAlignment.center,
-
Expanded
在 Column 和 Row 中代表着平均充满的作用,当有两个存在的时候默认均分充满。同时页可以设置 flex 属性决定比例。
new Column(
///主轴居中,即是竖直向居中
mainAxisAlignment: MainAxisAlignment.center,
///大小按照最小显示
mainAxisSize : MainAxisSize.min,
///横向也居中
crossAxisAlignment : CrossAxisAlignment.center,
children: <Widget>[
///flex默认为1
new Expanded(child: new Text("1111"), flex: 2,),
new Expanded(child: new Text("2222")),
],
);
Flutter 中,布局很多时候一层一层嵌套出来的,当然还有其他更高级的布局方式,这里就先不展开了。
四、Flutter 页面
Flutter 中除了布局的 Widget,还有交互显示的 Widget 和完整页面呈现的Widget,其中常见的有 MaterialApp、Scaffold、Appbar、Text、Image、FlatButton等,下面简单介绍这些 Wdiget。
类型 | 使用 |
---|---|
MaterialApp | 一般作为APP顶层的主页入口,可配置主题,多语言,路由等 |
Scaffold | 一般用户页面的承载Widget,包含appbar、snackbar、drawer等material design的设定。 |
Appbar | 一般用于Scaffold的appbar ,内有标题,二级页面返回按键等,当然不止这些,tabbar等也会需要它 。 |
Text | 显示文本,几乎都会用到,主要是通过style设置TextStyle来设置字体样式等。 |
RichText | 富文本,通过设置TextSpan,可以拼接出富文本场景。 |
TextField | 文本输入框 :new TextField(controller: //文本控制器, obscureText: "hint文本"); |
Image | 图片加载: new FadeInImage.assetNetwork( placeholder: "预览图", fit: BoxFit.fitWidth, image: "url"); |
FlatButton | 按键点击: new FlatButton(onPressed: () {},child: new Container()); |
实现一个简单完整的页面试试。直接上代码:
- 首先我们创建一个StatefulWidget:DemoPage。
- 然后在_DemoPageState 中,通过build创建了一个Scaffold。
- Scaffold内包含了一个AppBar和一个ListView。
- AppBar类似标题了区域,其中设置了 title为 Text Widget。
- body是ListView, 返回自定义Widget。
import 'package:flutter/material.dart';
import 'package:gsy_github_app_flutter/test/DemoItem.dart';
class DemoPage extends StatefulWidget {
@override
_DemoPageState createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
@override
Widget build(BuildContext context) {
///一个页面的开始
///如果是新页面,会自带返回按键
return new Scaffold(
///背景样式
backgroundColor: Colors.blue,
///标题栏,当然不仅仅是标题栏
appBar: new AppBar(
///这个title是一个Widget
title: new Text("Title"),
),
///正式的页面开始
///一个ListView,20个Item
body: new ListView.builder(
itemBuilder: (context, index) {
return new CustomItem(); //类似于ios的cell
},
itemCount: 20,
),
);
}
}
这里主要讲解都是一些入坑
常用的东西,方便大家首先对一些基础知识有个大概了解。
五、路由
Flutter 中的页面跳转一般是通过
Navigator
实现的,路由跳转又分为:带参数跳转和不带参数跳转。不带参数跳转比较简单,默认可以通过 MaterialApp 的路由表跳转,也可以使用PageRouteBuider
;而带参数的跳转自定义跳转动画,参数通过跳转页面的构造方法传递。常用的跳转有如下几种使用:
///不带参数的路由表跳转
Navigator.pushNamed(context, routeName);
///跳转新页面并且替换,比如登录页跳转主页
Navigator.pushReplacementNamed(context, routeName);
///跳转到新的路由,并且关闭给定路由的之前的所有页面
Navigator.pushNamedAndRemoveUntil(context, '/calendar', ModalRoute.withName('/'));
///带参数的路由跳转,并且监听返回
Navigator.push(context, new MaterialPageRoute(builder: (context) => new NotifyPage())).then((res) {
///获取返回处理
});
///带参数的路由跳转,自定义跳转动画
Navigator.push(context, new PageRouteBuider(pageBuilde: (context, anination, secondAnimation) => new NotifyPage())).then((res) {
///获取返回处理
});
同时我们可以看到,Navigator 的 push 返回的是一个 Future,这个Future 的作用是在页面返回时被调用的。也就是你可以通过 Navigator 的 pop 时返回参数,之后在 Future 中可以的监听中处理页面的返回结果。
六、网络请求
当前 Flutter 网络请求封装中,国内最受欢迎的就是 Dio 或者 http 了,这两个都是对dart请求进行了二次封装,使用起来非常方便。
这里看下一个Http网络请求的例子
/// 请求列表数据,返回model
static Future<FYContractListModelEntity> getSelectContractList(Map params,{String pre ="t8"})
async {
/// 获取请求url
String url = EnvirmentUtils.getBaseUrlByPre(pre,FYNetUrl.selectContractList);
final response = await http.post(url,body: params);
if(response.statusCode == 200){
/// 请求成功后对结果进行处理
final result = json.decode(Utf8Decoder().convert(response.bodyBytes));
return JsonConvert.fromJsonAsT<FYContractListModelEntity>(result);
}else{
/// 抛出异常
throw Exception('Failed to load ContractList json');
}
}
七、Json序列化
项目json解析是不可避免的操作,Dart的解析如果手动解析的话是非常复杂的,可以看下代码:
class OrderListItem {
List<Data> data;
Property property;
Page page;
Status status;
OrderListItem({this.data, this.property, this.page, this.status});
OrderListItem.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = new List<Data>();
(json['data'] as List).forEach((v) {
data.add(new Data.fromJson(v));
});
}
property = json['property'] != null
? new Property.fromJson(json['property'])
: null;
page = json['page'] != null ? new Page.fromJson(json['page']) : null;
status =
json['status'] != null ? new Status.fromJson(json['status']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data.map((v) => v.toJson()).toList();
}
if (this.property != null) {
data['property'] = this.property.toJson();
}
if (this.page != null) {
data['page'] = this.page.toJson();
}
if (this.status != null) {
data['status'] = this.status.toJson();
}
return data;
}
}
class Data {
int goodsLoadDate;
String orderSn;
String unDrawMoney;
int brokerPeriod;
String startCityName;
String goodsWeight;
int checkStatus;
String payStatusEnum;
int buttonStatus;
String carLength;
String driverMobile;
double noPayMoney;
String statusDesc;
String hasPay;
int isNew;
int needReceipt;
String buttonStatusDesc;
String endCityName;
String exceptionStatusEnum;
String backStatusEnum;
int driverId;
int backStatus;
String checkStatusEnum;
String driverName;
String waitPay;
int payStatus;
String carModel;
String goodsNum;
String goodsCubage;
String locationAddress;
int driverArrangeDeadline;
int expectDelayTime;
int expectGoodsUnloadDate;
int positionStatus;
Data(
{this.goodsLoadDate,
this.orderSn,
this.unDrawMoney,
this.brokerPeriod,
this.startCityName,
this.goodsWeight,
this.checkStatus,
this.payStatusEnum,
this.buttonStatus,
this.carLength,
this.driverMobile,
this.noPayMoney,-->
this.statusDesc,
this.hasPay,
this.isNew,
this.needReceipt,
this.buttonStatusDesc,
this.endCityName,
this.exceptionStatusEnum,
this.backStatusEnum,
this.driverId,
this.backStatus,
this.checkStatusEnum,
this.driverName,
this.waitPay,
this.payStatus,
this.carModel,
this.goodsNum,
this.goodsCubage,
this.locationAddress,
this.driverArrangeDeadline,
this.expectDelayTime,
this.expectGoodsUnloadDate,
this.positionStatus});
Data.fromJson(Map<String, dynamic> json) {
goodsLoadDate = json['goodsLoadDate'];
orderSn = json['orderSn'];
unDrawMoney = json['unDrawMoney'];
brokerPeriod = json['brokerPeriod'];
startCityName = json['startCityName'];
goodsWeight = json['goodsWeight'];
checkStatus = json['checkStatus'];
payStatusEnum = json['payStatusEnum'];
buttonStatus = json['buttonStatus'];
carLength = json['carLength'];
driverMobile = json['driverMobile'];
noPayMoney = json['noPayMoney'];
statusDesc = json['statusDesc'];
hasPay = json['hasPay'];
isNew = json['isNew'];
needReceipt = json['needReceipt'];
buttonStatusDesc = json['buttonStatusDesc'];
endCityName = json['endCityName'];
exceptionStatusEnum = json['exceptionStatusEnum'];
backStatusEnum = json['backStatusEnum'];
driverId = json['driverId'];
backStatus = json['backStatus'];
checkStatusEnum = json['checkStatusEnum'];
driverName = json['driverName'];
waitPay = json['waitPay'];
payStatus = json['payStatus'];
carModel = json['carModel'];
goodsNum = json['goodsNum'];
goodsCubage = json['goodsCubage'];
locationAddress = json['locationAddress'];
driverArrangeDeadline = json['driverArrangeDeadline'];
expectDelayTime = json['expectDelayTime'];
expectGoodsUnloadDate = json['expectGoodsUnloadDate'];
positionStatus = json['positionStatus'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['goodsLoadDate'] = this.goodsLoadDate;
data['orderSn'] = this.orderSn;
data['unDrawMoney'] = this.unDrawMoney;
data['brokerPeriod'] = this.brokerPeriod;
data['startCityName'] = this.startCityName;
data['goodsWeight'] = this.goodsWeight;
data['checkStatus'] = this.checkStatus;
data['payStatusEnum'] = this.payStatusEnum;
data['buttonStatus'] = this.buttonStatus;
data['carLength'] = this.carLength;
data['driverMobile'] = this.driverMobile;
data['noPayMoney'] = this.noPayMoney;
data['statusDesc'] = this.statusDesc;
data['hasPay'] = this.hasPay;
data['isNew'] = this.isNew;
data['needReceipt'] = this.needReceipt;
data['buttonStatusDesc'] = this.buttonStatusDesc;
data['endCityName'] = this.endCityName;
data['exceptionStatusEnum'] = this.exceptionStatusEnum;
data['backStatusEnum'] = this.backStatusEnum;
data['driverId'] = this.driverId;
data['backStatus'] = this.backStatus;
data['checkStatusEnum'] = this.checkStatusEnum;
data['driverName'] = this.driverName;
data['waitPay'] = this.waitPay;
data['payStatus'] = this.payStatus;
data['carModel'] = this.carModel;
data['goodsNum'] = this.goodsNum;
data['goodsCubage'] = this.goodsCubage;
data['locationAddress'] = this.locationAddress;
data['driverArrangeDeadline'] = this.driverArrangeDeadline;
data['expectDelayTime'] = this.expectDelayTime;
data['expectGoodsUnloadDate'] = this.expectGoodsUnloadDate;
data['positionStatus'] = this.positionStatus;
return data;
}
}
class Property {
int searchType;
int systemTime;
Property({this.searchType, this.systemTime});
Property.fromJson(Map<String, dynamic> json) {
searchType = json['searchType'];
systemTime = json['systemTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['searchType'] = this.searchType;
data['systemTime'] = this.systemTime;
return data;
}
}
class Page {
int totalCou;
int curPage;
int totalPage;
int nextPage;
bool useCache;
int pageSize;
bool queryCount;
Page(
{this.totalCou,
this.curPage,
this.totalPage,
this.nextPage,
this.useCache,
this.pageSize,
this.queryCount});
Page.fromJson(Map<String, dynamic> json) {
totalCou = json['totalCou'];
curPage = json['curPage'];
totalPage = json['totalPage'];
nextPage = json['nextPage'];
useCache = json['useCache'];
pageSize = json['pageSize'];
queryCount = json['queryCount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['totalCou'] = this.totalCou;
data['curPage'] = this.curPage;
data['totalPage'] = this.totalPage;
data['nextPage'] = this.nextPage;
data['useCache'] = this.useCache;
data['pageSize'] = this.pageSize;
data['queryCount'] = this.queryCount;
return data;
}
}
class Status {
int code;
String desc;
Status({this.code, this.desc});
Status.fromJson(Map<String, dynamic> json) {
code = json['code'];
desc = json['desc'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['code'] = this.code;
data['desc'] = this.desc;
return data;
}
}
所以 json_annotation
插件就诞生了,只需写入类名和返回的json数据即可自动生成
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons
json_annotation: ^2.0.0
dev_dependencies:
flutter_test:
sdk: flutter
json_serializable: ^2.0.0
可以自己在项目中操作一把看下,非常方便。
八、Redux
在前端领域,Redux
并不是一个陌生的概念,作为全局状态管理机,用于 Flutter 中再合适不过,简单来说就是:它可以跨控件管理、同步State 。
前面已经讲了,在 Flutter
中 是通过实现 State
与 setState
来渲染和改变 StatefulWidget 的,如果使用了flutter_redux 会有怎样的效果?
比如把用户信息存储在 redux
的 store
中, 好处在于: 比如某个页面修改了当前用户信息,所有绑定的该 State 的控件将由 Redux 自动同步修改,State 可以跨页面共享。
redux 中主要引入了 action、reducer、store 概念:
- action 简单点就是动作,通过发起一个action来告诉Reducer该更新状态了
- reducer 用于根据 action 产生新状态
- store 位于整个APP的顶层,用于存储和管理 state
直接上代码:
8.1. 创建State
///创建State,全局Redux store 的对象,保存State数据
//定义一个state
class ReduxState {
String name;
ReduxState.initState() : name = "666";
}
8.2. 创建action
//定义action
enum Action {
Change
}
8.3. 创建reducer
//定义reducer
ReduxState getReduce(ReduxState state, action) {
if(action == Action.Change) {
String nname = "1";
state.name = state.name + nname;
}
return state;
}
8.4. 创建全局Store
在main.dart中创建一个全局的store
main() {
final store = Store<ReduxState>(
getReduce,
initialState: ReduxState.initState()
);
runApp(ReduxDemo3(store,));
}
8.5. 将Store跟根Widget关联
注意:
- 最顶层必须是 StoreProvider 开始
- StoreBuilder后要跟上我们定义的那个State类,要不会报错,
class ReduxDemo3 extends StatelessWidget {
final Store<ReduxState> store;
ReduxDemo3(this.store);
@override
Widget build(BuildContext context) {
return StoreProvider(
store: store,
child: StoreBuilder<ReduxState>(builder: (BuildContext context, Store<ReduxState> store){
return MaterialApp(
title: 'ReduxDemo3',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: FirstPage(),
);
})
);
}
}
8.6. 一级子界面构建
注意:builder方法里有2个值,context和store,我们自定义的State类可以从store中获取
@override
Widget build(BuildContext context) {
return StoreBuilder<ReduxState>(
builder: (BuildContext context, Store<ReduxState> store){
return Scaffold(
appBar: AppBar(
title: Text("ReduxDemo3"),
),
body: Center(
child: Column(
children: <Widget>[
Text(store.state.name),
SizedBox(height: 100,),
FlatButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context){
return NextPage();
}));
},
child: Text("下一页")
)
],
)
),
);
}
);
}
8.7. 二级子界面构建
State数据的修改是由Store来发起Action,通知Reducer修改数据,方法为store.dispatch(定义的action)
@override
Widget build(BuildContext context) {
return StoreBuilder<ReduxState>(
builder: (BuildContext context, Store<ReduxState> store){
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Text(store.state.name),
SizedBox(height: 100,),
FlatButton(
onPressed: (){
store.dispatch(Action.Change);
},
child: Text("点击变换数据")
)
],
)
),
);
}
);
}
最终效果:
image
8.8. StoreBuilder和StoreConnector
例子里的界面构建使用的是StoreBuilder来构建,也可以使用 ==StoreConnector== 来构建,两者就差一个参数。
StoreConnector主要是有个数据转化的作用,可以对数据先做一些转化操作再赋值到组件上
/// 多一个ViewModel
class StoreConnector<S, ViewModel> extends StatelessWidget
class StoreBuilder<S> extends StatelessWidget
可以修改第二个界面里的body的代码,将显示的Text换成用StoreConnector来包装,效果是一样的
body: Center(
child: Column(
children: <Widget>[
StoreConnector<ReduxState, String>(
///转换为要使用的 name 字符串
converter: (store) => store.state.name,
builder: (BuildContext context, String name) {
return Text(name);
},
),
SizedBox(height: 100,),
StoreBuilder<ReduxState>(
builder: (context, store) {
return FlatButton(
onPressed: (){
store.dispatch(Action.Change);
},
child: Text("点击变换数据")
);
}
),
],
)
),
StoreConnector 需要两个泛型
- 一个是我们创建的 State(ReduxState)
- 一个是 ViewModel
StoreConnector 要定义两个函数
- 一个是 converter,转化函数,从 Store 中拿出修改的数据 store.state.name
- 一个是 builder,将 converter 返回的 name 进一步转化为界面:Text(name)。
ViewModel决定了converter(转换函数)那边的返回值类型,这边我们将它定义为String,因为转换函数里返回的是ReduxState里的name字段。
这里就是对
flutter
入门的一些简单知识分享,一些概念性的东西这里不一一分享,大家看官网就可以看到,这里主要针对一些重要概念和一些坑进行分析,希望对大家有所帮助。
网友评论