首页 > 解决方案 > 滚动控制器不适用于futurebuilder

问题描述

我有一个通过偏移量上传数据的 api 调用,我的目标是在用户向下滚动时加载 10 x 10,问题是我无法向下滚动并显示更多数据:这是我的片段:

class Body extends StatefulWidget {
  @override
  _BodyState createState() => _BodyState();
}

class _BodyState extends State<Body> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          HomeHeader(),
          ProductsGridViewInfiniteScroll(),
        ],
      ),
    );
  }
}

这里的滚动控制器似乎不起作用:

class ProductsGridViewInfiniteScroll extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return ProductsGridViewInfiniteScrollState();
  }
}

class ProductsGridViewInfiniteScrollState
    extends State<ProductsGridViewInfiniteScroll> {
  Future<ProductList> products;
  int offset;
  ScrollController _controller;

  _scrollListener() {
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        !_controller.position.outOfRange) {
      setState(() {
        offset += 10;
        products = loadProductsByIdService(1, offset, 10);
      });
    }
  }

  @override
  void initState() {
    offset = 0;
    products = loadProductsByIdService(1, offset, 10);
    _controller = ScrollController();
    _controller.addListener(_scrollListener);
    super.initState();
  }

  Widget build(BuildContext context) {
    return FutureBuilder<ProductList>(
        future: products,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return GridView.builder(
                controller: _controller,
                itemCount: snapshot.data.products.length,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    crossAxisSpacing: 4.0,
                    mainAxisSpacing: 10.0),
                shrinkWrap: true,
                physics: ScrollPhysics(),
                itemBuilder: (BuildContext ctx, index) {
                  return Container(
                    alignment: Alignment.center,
                    child: ProductCard(product: snapshot.data.products[index]),
                  );
                });
          } else {
            return SizedBox();
          }
        });
  }
}
Future<ProductList> loadProductsByIdService(serviceid, offset, limit) async {
  var datamap = {'service_id': serviceid, 'offset': offset, 'limit': limit};
  var data = json.encode(datamap);
  ProductList products;

  final response = await http.post(Uri.parse(PRODUCTS),
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: data,
      encoding: Encoding.getByName("utf-8"));

  if (response.body.isNotEmpty) {
    if (response.statusCode == 200) {
      products = ProductList.fromJson(json.decode(response.body));
    }
  } else {
    throw Exception('echec de chargement des produits');
  }

  return products;
}

每次滚动到达屏幕底部时,我都想重建构建功能并更新产品变量,请提供帮助;

标签: flutterflutter-futurebuilder

解决方案


看起来ClampingScrollPhysics是 Android 和BouncingScrollPhysics中滚动物理的默认行为。很可能您在 IOS 上运行,因此默认情况下您使用的是 BouncingScrollPhysics。如果是这种情况,请将您的 if 条件更改为:

_scrollListener() {
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        _controller.position.outOfRange) {
      _controller.jumpTo(0);
      setState(() {
        offset += 10;
        products = getProducts(offset, limit);
      });
    }
  }

当使用弹跳物理时,滚动通过 max scrolling extend 并且 outOfRange 变为 true。您需要将控制器偏移量重置回 0,因为它将继续多次调用侦听器,从而通过增加偏移量来跳过页面。


推荐阅读