首页 > 解决方案 > 刷新 ListView.builder 时颤动它从开始而不是从 maxScrollExtent 点返回

问题描述

我是 Flutter 的新手,我遇到了一个问题。

到目前为止,我正在从 Web 服务异步(Json)获取数据。所以在构建方法中,我FutureBuilder为 Scaffold 的 body 参数使用了一个小部件。并且它的 'builder' 参数(FutureBuilder小部件)返回 aListView.builder以显示数据。我也ScrollController用于滚动。

是我达到最大滚动点的时候了,我再次调用该服务以获取下一页数据等等......

问题是,当我通过滚动“更改页面”时,它会正确显示数据,但它从第一行数据开始,而不是从我到达该maxScrollExtent点的地方开始。

因此,如果第一个“快照”有 25 行,第二个有 15 行,那么当我转到第二个时,它从第 1 行开始,而不是从第 26 行开始,尽管数据行的总数是 40 正确。

结果我没有平滑的滚动。到目前为止,我已经被困了足够长的时间,我不知道我错过了什么。我是否必须使用页面存储键(我看到了颤振团队的视频,但我没有找到解决我的问题的优势)。有什么提示吗?下面是代码示例。

class _MyAppState extends State<MyApp> {
  
  final ScrollController _controller = ScrollController();
  @override
  void initState() {
    super.initState();
    _controller.addListener(_scrollListener);
  }
  void _scrollListener() {
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        !_controller.position.outOfRange) {

      if (nextDataSet != null) {
        print('nextDataSet = ' + nextDataSet);
        setState(() {
          inDataSet = nextDataSet;
        });
      } else {
        print('nextDataSet = NULL');
      }

  }

  Future<Post> fetchPost([String dataSet]) async {
  ...
  return Post.fromJson(json.decode(utf8.decode(response.bodyBytes)));
  }

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (context) => Scaffold(
        ...
        body: FutureBuilder<Post>(
                  future: fetchPost(inDataSet),
                  builder: _buildList,
                ),
        ),
      ),
    );
    }

  Widget _buildList(BuildContext context, AsyncSnapshot snapshot) {
     ... /*code that eventually fills the lists of strings 
         progressivePartyListSec, progressivePartyListThird*/
     ...
     return ListData(controller: _controller, listEidosPerigr: 
     progressivePartyListSec, listPerigr: progressivePartyListThird );
  }

}

class ListData extends StatelessWidget {

  final ScrollController controller;
  final List<String> listEidosPerigr;
  final List<String> listPerigr;

  ListData({this.controller,
    this.listEidosPerigr,
    this.listPerigr});

  @override
  Widget build(BuildContext context) {

    return ListView.builder(
        controller: controller,
        itemCount: rowsSelected,
        itemBuilder: (context, i) {
          return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  removeAllHtmlTags(listEidosPerigr[i]),
                  style: TextStyle(
                      fontWeight: FontWeight.bold, color: Colors.blue),
                ),
                new RichText(
                  text: new TextSpan(
                      text: listPerigr[i].replaceAllMapped('<BR>', (Match m) => '').replaceAllMapped('<b>', (Match m) => '').replaceAllMapped('</b>', (Match m) => ''),
                      style: DefaultTextStyle.of(context).style,
                  ),
                ),
              ]);
        });
  }
}

标签: flutter

解决方案


经过一些研究,我在以下链接中找到了解决方案:Flutter:创建一次加载一个页面的 ListView

非常感谢 AbdulRahman AlHamali。

基本上,在我发布的上述代码中,我为 ListView.builder 使用了另一个参数,它是以下键:PageStorageKey('offset'),

最后,正如 AbdulRahman 在他的文章中所写,我在我的构建方法中使用 KeepAliveFutureBuilder 作为 FutureBuilder 的包装器...

body: KeepAliveFutureBuilder(
            //child: FutureBuilder<Post>(
                future: fetchPost(inDataSet),
                builder: _buildList,
              //),
          ),

推荐阅读