如何实现对streambuilder的pull_to_refresh

时间:2019-07-15 11:55:20

标签: flutter dart

我正在尝试实现pull_to_refresh。我有两个我将要使用的无状态小部件。首先是_ProductCategoryDetailPageState,这里是代码

  @override
  Widget build(BuildContext context) {
    return Material(
        child: Scaffold(
        appBar: AppBar(
          title: Text(widget.categoryName),
        ),
        body: Container(
          height: MediaQuery.of(context).size.height,
          child: Column(
            children: <Widget>[
              Divider(
                height: 20.0,
              ),
              Flexible(
                  child:StreamBuilder<List<Products>>(
                stream: _productController.stream,
                builder: (context, snapshot) {
                    if (snapshot.hasError) {
                      return errMess(context, "Failed to fetch data");
                    } else {
                      if (snapshot.hasData) {
                        if (snapshot.data.length > 0) {
                          return ProductList(category: snapshot.data);
                        } else {
                          return errMess(context,
                              "There is no available product in this category");
                        }
                      } else {
                        return errMess(context,
                            "There is no available product in this category");
                      }
                    }
                },
              )),
              Divider(
                height: 25.0,
              ),
            ],
          ),
        )));
  }

  loadProduct(String categoryId, int limit, int offset) async {
    List<Products> products = await fetchProducts(http.Client(), categoryId, limit, offset);
    _productController.sink.add(products);
  }
  static List<Products> parseProducts(String responseBody) {
    final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
    return parsed.map<Products>((json) => Products.fromJson(json)).toList();
  }

  Future<List<Products>> fetchProducts(http.Client client, String categoryId, int limit, int offset) async {
    final response = await http.post(Configuration.url +
        "api/getProducts/" +
        categoryId +
        "/" +
        limit.toString() +
        "/" +
        offset.toString());
    if (response.statusCode < 200 || response.statusCode > 300) {
      throw new Exception('Failed to fetch data');
    } else {
      return compute(parseProducts, response.body);
    }
  }

这是我的第二个无状态小组件

class _ProductListState extends State<ProductList> {
  int limit = 0;
  int offset = 4;

  RefreshController _refreshController2 =
      RefreshController(initialRefresh: false);

  @override
  Widget build(BuildContext context) {
    return SmartRefresher(
      child: new GridView.builder(
        itemCount: widget.category.length,
        gridDelegate:
            new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
        itemBuilder: (BuildContext context, int index) {
          return new GestureDetector(
            onTap: () {
              print("Product detail");
            },
            child: Card(
              semanticContainer: true,
              clipBehavior: Clip.antiAliasWithSaveLayer,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded(
                    child: Image.network(
                      Configuration.url +
                          "assets/app_assets/" +
                          widget.category[index].productImage,
                      width: 250,
                      height: 250,
                      filterQuality: FilterQuality.low,
                    ),
                  ),
                  SizedBox(
                    height: 25,
                  ),
                  Text(
                    widget.category[index].productName,
                    style: TextStyle(fontSize: 15.0),
                  ),
                  SizedBox(
                    height: 25,
                  ),
                ],
              ),
            ),
          );
        },
      ),
      controller: _refreshController2,
      enablePullUp: true,
      header: MaterialClassicHeader(),
      onRefresh: () {
        _onRefresh(_refreshController2, widget.category,
            widget.category[0].categoryId);
      },
      onLoading: () {
        _onLoading(_refreshController2, widget.category,
            widget.category[0].categoryId);
      },
    );
  }

  void _onLoading(RefreshController controller, List<Products> data,String categoryId) async {
    await Future.delayed(Duration(milliseconds: 2000));
    setState(() {
      limit = limit + offset;
      offset = 6;
    });

   _ProductCategoryDetailPageState().loadProduct(categoryId, limit, offset);

    controller.loadComplete();
  }

  void _onRefresh(RefreshController controller, List<Products> data,
      String categoryId) async {
    await Future.delayed(Duration(milliseconds: 1000));
    controller.refreshCompleted();
  }
}

当我拉网格时没有错误,但是数据没有改变。在我检查了这部分之后

    Flexible(
                      child:StreamBuilder<List<Products>>(
                    stream: _productController.stream,
                    builder: (context, snapshot) {
print("run")
                        if (snapshot.hasError) {
                          return errMess(context, "Failed to fetch data");
                        } else {
                          if (snapshot.hasData) {
                            if (snapshot.data.length > 0) {
                              return ProductList(category: snapshot.data);
                            } else {
                              return errMess(context,
                                  "There is no available product in this category");
                            }
                          } else {
                            return errMess(context,
                                "There is no available product in this category");
                          }
                        }
                    },
                  )),

您可以看到我添加了print("run"),它只显示了一次。

我的完整脚本https://gist.github.com/bobykurniawan11/04f2584c6de97f1d9324bfe3b24f669f

1 个答案:

答案 0 :(得分:1)

这在您创建State对象的新State实例时不起作用。例如,您应该使用回调将两个小部件连接起来。

_ProductCategoryDetailPageState().loadProduct(categoryId, limit, offset);

赞:

// Custom callback function
typedef void OnLoadProductsFunction(String categoryId, int limit, int offset); 

class ProductList extends StatefulWidget {
    OnLoadProductsFunction onLoad;

    ProductList({
        this.category,
        this.onLoad,
    })
}

...

 void _onLoading(RefreshController controller, List<Products> data,String categoryId) async {
    await Future.delayed(Duration(milliseconds: 2000));
    setState(() {
      limit = limit + offset;
      offset = 6;
    });

    widget.onLoad(categoryId, limit, offset);

    controller.loadComplete();
}

...


// In the parent widget
return ProductList(
    category: snapshot.data
    onLoad: (categoryId, limit, offset) {
        loadProduct(categoryId, limit, offset);
    }
);

这样,将通过回调函数更新streamcontroller。您还需要执行的另一种选择是将StreamController实例传递到ProductList小部件,并且是将产品列表添加到接收器的孩子。