flutter 使用Bloc和refresh 進行搭建頁面

嬌嫩的黃瓜發表於2019-04-30

主要解決問題是 頁面請求資料 資料進行動態重新整理 (重新整理某些控制元件)

首先進行建立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}"),
          ],
        ),
      ),
    );
  }
}


複製程式碼

設定幀動畫



/// 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+rxdart

具體效果如下

flutter  使用Bloc和refresh 進行搭建頁面
flutter  使用Bloc和refresh 進行搭建頁面
flutter  使用Bloc和refresh 進行搭建頁面

相關文章