【问题标题】:scrollcontroller doesn't work with futurebuilder滚动控制器不适用于futurebuilder
【发布时间】:2021-08-10 14:06:17
【问题描述】:

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

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;
}

我想在每次滚动到达屏幕底部时重建构建函数并更新产品变量,请帮助;

【问题讨论】:

  • 您是否重新启动了应用程序?当我们定义控制器时,应用程序需要重新启动。请检查是否执行了 setState。
  • 我按照你说的重新启动了应用程序,但是向下滚动时只加载了 10 个产品,没有任何反应,如果你不介意我如何检查 setState 是否被执行?
  • 做一个 print("something") 应该在终端打印一些东西。
  • 是否显示了任何产品?
  • 是的,前 10 个产品

标签: flutter flutter-futurebuilder


【解决方案1】:

看起来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,因为它会多次调用侦听器,从而通过增加偏移量来跳过页面。

【讨论】:

  • 其实我是用chrome调试的,请问在真机上能不能用?您的解决方案也不起作用
  • @ELHITFatima 很抱歉,我已经在我的 Android 设备上测试过了。它有效!
  • 是的,我正在使用不支持虚拟化的计算机上工作,所以我无法在模拟器上运行该应用程序,所以我将在另一台计算机上进行测试
  • @ELHITFatima 您可以尝试将物理设置为 BouncingScrollPhysics,因为我的答案适用于这类物理。
  • @eduardHasanag 实际上它可以工作 `physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),` 将收缩包装设置为 true,我还通过 itembuilder 中的索引条件修复了没有滚动控制器的问题if (index == snapshot.data.products.length - 1 ){ products = loadProductsByIdService(serviceId, offset += 10, limit); }
【解决方案2】:

如果有人遇到同样的问题,这是不使用 FutureBuilder 对我有用的最终解决方案:

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new HomeState();
}

class HomeState extends State<Home> {
  static int offset = 0;
  ScrollController _sc = new ScrollController();
  bool isLoading = false;
  ProductList products = new ProductList(products: []);

  @override
  void initState() {
    this._getMoreData(1, offset, 10);
    super.initState();
    _sc.addListener(() {
      if (_sc.position.pixels == _sc.position.maxScrollExtent) {
        _getMoreData(1, offset += 10, 10);
      }
    });
  }

  @override
  void dispose() {
    _sc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _buildGrid();
  }

  Widget __buildGrid() {
    return GridView.builder(
        controller: _sc,
        itemCount: products.products.length + 1,
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
        ),
        shrinkWrap: true,
        physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
        itemBuilder: (BuildContext ctx, index) {
          if (index == products.products.length) {
            return Padding(
              padding: const EdgeInsets.all(8.0),
              child: new Center(
                child: new Opacity(
                  opacity: isLoading ? 1.0 : 00,
                  child: new CircularProgressIndicator(),
                ),
              ),
            );
          } else {
            return Container(
              alignment: Alignment.topLeft,
              // child: Flexible(
              child: ProductCard(product: products.products[index]),
              // ),
            );
          }
        });

   
  }

  void _getMoreData(serviceid, offset, limit) async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      var datamap = {'service_id': serviceid, 'offset': offset, 'limit': limit};
      var data = json.encode(datamap);
      ProductList ps;

      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.statusCode == 200) {
        ps = ProductList.fromJson(json.decode(response.body));
        setState(() {
          isLoading = false;
          products.products.addAll(ps.products);
          // offset += 10;
        });
      }
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-12
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    相关资源
    最近更新 更多