如何实现对streambuilder的pull_to_refresh [英] How to implement pull_to_refresh to streambuilder
问题描述
我正在尝试实施 pull_to_refresh 。我有两个我将要使用的无状态小部件。首先是 _ProductCategoryDetailPageState
这是代码
i'm trying to implement pull_to_refresh . I have two stateless widget that i will use . First is _ProductCategoryDetailPageState
here is the code
@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);
}
}
这是我的第二个无状态小组件
and here is my second stateless widget
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();
}
}
当我拉网格时没有错误,但是数据不变。在我检查了这部分之后
when i pull the grid there is no error , but the data is not change. After i check on this part
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)
,它仅显示一次。
As you can see i adding print("run")
, it just only showing once.
我完整脚本 https://gist.github.com/bobykurniawan11/04f2584c6de97f1d9324bfe3b24f669> b $ b
my full script https://gist.github.com/bobykurniawan11/04f2584c6de97f1d9324bfe3b24f669f
推荐答案
这在您创建State对象的新State实例时将不起作用。
This won't work as you are creating a new State instance of the State object. You should connect both widgets with a callback for example.
_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
实例传递给 ProductList
小部件,并且该子项是添加产品列表的子级到水槽。
Doing it this way the streamcontroller will be updated from the callback function. Other option you have is to pass the StreamController
instance to the ProductList
widget and is the child who adds the list of products to the sink.
这篇关于如何实现对streambuilder的pull_to_refresh的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!