主要解決問題是 頁面請求數據 數據進行動態刷新 (刷新某些控件)bash
首先進行建立bloc服務器
//bloc基類
import 'package:flutter/material.dart';
class BaseBlocWidget{
Stream streams() => null;
Widget streamBuilder<T>({
T initalData,
Function success,
Function error,
Function loading,
Function finished,
Stream<T> stream,
}) {
return StreamBuilder(//StreamBuilder 這個是比較主要的
stream: stream,
initialData: initalData,
builder: (context, AsyncSnapshot<T> snapshot) {
if (finished != null) {
finished();
}
if (snapshot.hasData) {
if (success != null) return success(snapshot.data);
} else if (snapshot.hasError) {
if (error != null) return error(snapshot.hasError);
} else {
if (loading != null) return loading();
}
});
}
}
複製代碼
import 'package:flutter/widgets.dart';
import 'package:flutter_tticar/ui/bloc/BaseBlocWidget.dart';
import 'package:flutter_tticar/ui/comment/http/TTicarWork.dart';
import 'package:flutter_tticar/ui/setting/bean/GoodsCollectBean.dart';
import 'package:rxdart/rxdart.dart';
class CounterBloc extends BaseBlocWidget {
//GoodsCollectBean 爲網絡接口請求返回 解析的bean
final _fetcher = new PublishSubject<GoodsCollectBean>();
streams() => _fetcher.stream;
void dispose() {
if (!_fetcher.isClosed) {
_fetcher.close();
}
}
void fetchQueryList(String pageNum) async {//解析數據
_refreshDate(pageNum, (map) => GoodsCollectBean.fromJson(map));
}
void _refreshDate(String pageNum, Function handleData) async {
new TTicarWork().loadCollectGood(pageNum, "20").listen((request) {
try{
_fetcher.sink.add(handleData(request)); //異步回調
}catch(e){//解析異常等
_fetcher.sink.addError(e,null);
}
}, onError: (e) {//請求異常等
_fetcher.sink.addError(e, null);
});
}
}
複製代碼
頁面基本邏輯操做網絡
import 'package:flutter/material.dart';
import 'package:flutter_tticar/ui/comment/http/TTicarWork.dart';
import 'package:flutter_tticar/ui/comment/status/StatusView.dart';
import 'package:flutter_tticar/ui/setting/bean/BaseRequestBean.dart';
import 'package:flutter_tticar/ui/setting/bean/GoodsCollectBean.dart';
import 'package:flutter_tticar/ui/setting/collect/item/GoodsItem.dart';
import 'package:flutter_tticar/ui/setting/myCollectBloc/CounterBloc.dart';
import "package:pull_to_refresh/pull_to_refresh.dart";
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:fluttertoast/fluttertoast.dart';
class GoodsCollectPage extends StatefulWidget {
@override
GoodsCollectPageState createState() => new GoodsCollectPageState();
}
class GoodsCollectPageState extends State<GoodsCollectPage> {
CounterBloc _blocProvider = new CounterBloc();
StatusView _statusView = new StatusView();
RefreshController _refreshController;
ScrollController _scrollController;
int pageNum = 1; //設置頁數
int pageSize = 1; //設置頁數
bool refreshUp = true; //判斷時候是上拉加載仍是下拉刷新
bool refresh = false; //判斷是第幾回(解決 pull_to_refresh 出現的問題)
List<ListBean> dataList = [];
@override
void initState() {
//設置初始數據
super.initState();
_blocProvider.fetchQueryList("$pageNum");
_scrollController = new ScrollController();
_refreshController = new RefreshController();
}
@override
void dispose() {
_blocProvider.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return _buildData();
}
Widget _buildData() {
return _blocProvider.streamBuilder<GoodsCollectBean>(
//數據返回回調
success: (data) {
var request = data as GoodsCollectBean;
if (null != request.result && request.success) {
//判斷有數據
pageSize = int.parse(request.result.size);
if (pageNum == 1) {
dataList.clear();
}
dataList.addAll(request.result.list);
} else if (pageNum == 1 &&
request.success &&
request.result.list.length == 0) {
// 第一頁 無數據
return _statusView.empty("喜歡就藏起來啊,別客氣~");
} else {
// 服務器有異常
return _statusView.empty(request.msg);
}
if (refresh) {
_refreshController.sendBack(refreshUp, RefreshStatus.completed);
}
_refreshController.sendBack(
false,
pageSize > pageNum
? RefreshStatus.canRefresh
: RefreshStatus.completed);
return new SmartRefresher(
enablePullDown: true,
enablePullUp: true,
controller: _refreshController,
onRefresh: _onRefresh,
headerBuilder: (context, mode) {
return new ClassicIndicator( //這個能夠定義公共組件
mode: mode,
height: 45.0,
releaseText: '鬆開手刷新',
refreshingText: '刷新中',
completeText: '刷新完成',
failedText: '刷新失敗',
idleText: '下拉刷新',
);
},
footerBuilder: (context, mode) {
return new ClassicIndicator(
mode: mode, height: 45, completeText: "加載完成");
},
child: new ListView.builder(
controller: _scrollController,
itemCount: dataList.length,
itemBuilder: (context,index){
return _getDatas(dataList[index]);
},
));
},
stream: _blocProvider.streams(), //必須設置的屬性
error: (msg) {
return _statusView.error(msg); //解析或者接口異常頁面
},
loading: () {
return _statusView.showLoading(); //加載頁
});
}
void _onRefresh(bool up) {
refreshUp = up;
refresh = true;
if (up) {
pageNum = 1;
//headerIndicator callback
_refreshDate("$pageNum");
} else {
if (pageSize > pageNum) {
pageNum++;
//footerIndicator Callback
_refreshDate("$pageNum");
}
}
}
//請求數據
void _refreshDate(String pageNum) {
_blocProvider.fetchQueryList(pageNum);
}
Widget _getDatas(ListBean item) {
return new Card(
color: Colors.white,
elevation: 0,
margin: new EdgeInsets.only(left: 10, right: 10, top: 10),
child:new Text("本身添加列表數據"),
);
}
}
複製代碼
缺省頁工具類異步
import 'package:flutter/material.dart';
import 'package:flutter_tticar/ui/comment/utile/FrameAnimationImage.dart';
//缺省頁工具類
class StatusView {
AnimationController controller;
Animation<double> animation;
List<String> images = [];
Widget showLoading() {
for (var i = 0; i < 12; i++) {
images.add("static/images/donghua_000$i.png");
}
return new Container(
color: Colors.white,
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new FrameAnimationImage(
assetList: images,
width: 100,
height: 100,
interval: 100,
),
Text("正在加載中……")
],
),
),
);
}
Widget error(Exception msg) {
String errMsg="";
return new Container(
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("static/images/ic_status_view_empty_data.png", width: 100,
height: 100),
Text("服務器出現異常請稍後再試"),
],
),
),
);
}
Widget empty(msg) {
return new Container(
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("static/images/icon_no_collection.png", width: 100,
height: 100),
Text("${msg}"),
],
),
),
);
}
}
複製代碼
設置幀動畫async
/// Flutter FrameAnimation 逐幀動畫(這個是在別處引用的 具體地址忘了)
import 'package:flutter/material.dart';
class FrameAnimationImage extends StatefulWidget {
final List<String> assetList;
final double width;
final double height;
final int interval;
FrameAnimationImage(
{this.assetList, this.width, this.height, this.interval = 200});
@override
State<StatefulWidget> createState() {
return _FrameAnimationImageState();
}
}
class _FrameAnimationImageState extends State<FrameAnimationImage>
with SingleTickerProviderStateMixin {
// 動畫控制
Animation<double> _animation;
AnimationController _controller;
int interval = 200;
@override
void initState() {
super.initState();
if (widget.interval != null) {
interval = widget.interval;
}
final int imageCount = widget.assetList.length;
final int maxTime = interval * imageCount;
// 啓動動畫controller
_controller = new AnimationController(
duration: Duration(milliseconds: maxTime), vsync: this);
_controller.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_controller.forward(from: 0.0); // 完成後從新開始
}
});
_animation = new Tween<double>(begin: 0, end: imageCount.toDouble())
.animate(_controller)
..addListener(() {
setState(() {
// the state that has changed here is the animation object’s value
});
});
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
int ix = _animation.value.floor() % widget.assetList.length;
List<Widget> images = [];
// 把全部圖片都加載進內容,不然每一幀加載時會卡頓
for (int i = 0; i < widget.assetList.length; ++i) {
if (i != ix) {
images.add(Image.asset(
widget.assetList[i],
width: 0,
height: 0,
));
}
}
images.add(Image.asset(
widget.assetList[ix],
width: widget.width,
height: widget.height,
));
return Stack(alignment: AlignmentDirectional.center, children: images);
}
}
複製代碼
網絡請求請參考 dio+rxdartide
具體效果以下工具