Flutter List + Pull加载更多数据并不等待数据加载完成导致列表/滚动变得不稳定

问题描述 投票:0回答:2

如果你创建一个新的Flutter项目并包含依赖项,然后替换你的main.dart文件,你应该就我在这个问题上的位置。


我离开了原来的负载:使用Future.delayed,但似乎并不重要。我知道我的问题是什么,但我无法提出更好的解决方案。

1)我似乎没有使用我的snapshot.data而是我只是用str创建一个空列表然后我只是addAll并使用它。所以我喜欢不这样做,我最初使用的是snapshot.data,但当我试图“拉动加载更多数据”时会遇到问题,这会在滚动到列表底部后发生。

我当前执行此操作的方法的问题是,如果您拉动以加载更多用户,然后在用户加载之前尝试再次拉动,则应用程序会中断并且不会等待数据正确加载。我相信我需要在这个库load:easy_refresh中完成所有这些...但我不知道如何重写我的代码来实现这一目标。

如何使用snapshot.data加载我的数据,然后当我进行刷新时,我将100个用户追加到该列表,但是UI在完成加载之前等待列表更新。我是否会更好地放置阻止UI元素并在str列表更新后?加载新用户时,我取消阻止用户界面?哪种方式感觉很乱,而不是解决这个问题的正确方法。插件本身应该能够进行加载,当它准备就绪时,它会停止列表下的微调器并显示“已完成”。

pubspec.yaml

dependencies:
flutter:
  sdk: flutter

flutter_easyrefresh: ^1.2.7
http: ^0.12.0+2

main.dart

  import 'package:flutter/material.dart';
  import 'dart:async';
  import 'dart:convert';
  import 'package:flutter_easyrefresh/easy_refresh.dart';
  import 'package:http/http.dart' as http;

  void main() => runApp(MyApp());

  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          backgroundColor: Colors.white
        ),
        home: DuelLeaderBoards(),
      );
    }
  }


  class DuelLeaderBoards extends StatefulWidget {
    @override
    _DuelLeaderBoardsState createState() => _DuelLeaderBoardsState();
  }

  class _DuelLeaderBoardsState extends State<DuelLeaderBoards> {
    List<Entry> str = [];
    GlobalKey<EasyRefreshState> _easyRefreshKey = new GlobalKey<EasyRefreshState>();
    GlobalKey<RefreshHeaderState> _headerKey = new GlobalKey<RefreshHeaderState>();
    GlobalKey<RefreshHeaderState> _connectorHeaderKey = new GlobalKey<RefreshHeaderState>();
    GlobalKey<RefreshFooterState> _footerKey = new GlobalKey<RefreshFooterState>();
    GlobalKey<RefreshFooterState> _connectorFooterKey = new GlobalKey<RefreshFooterState>();

    Future<LeaderBoards> getLeaderBoards(start) async {
      String apiURL = 'https://stats.quake.com/api/v2/Leaderboard?from=$start&board=duel&season=current';

      final response = await http.get(apiURL);
      if (response.statusCode == 200) {
        final responseBody = leaderBoardsFromJson(response.body);
        return responseBody;
      } else {
        throw Exception('Failed to load Data');
      }
    }

    void updateLeaderBoardList(e) async {
      setState(() {
        str.addAll(e.entries);
      });
    }

    @override
    void initState() {
      getLeaderBoards(0).then((onValue) => str = onValue.entries );
      super.initState();
    }

    @override
    Widget build(BuildContext context) {
      Widget header = ClassicsHeader(
        key: _headerKey,
        refreshText: "pullToRefresh",
        refreshReadyText: "releaseToRefresh",
        refreshingText: "refreshing...",
        refreshedText: "refreshed",
        moreInfo: "updateAt",
        bgColor: Colors.transparent,
        textColor: Colors.white,
      );
      Widget footer = ClassicsFooter(
        key: _footerKey,
        loadHeight: 50.0,
        loadText: "pushToLoad",
        loadReadyText: "releaseToLoad",
        loadingText: "loading",
        loadedText: "loaded",
        noMoreText: "Finished",
        moreInfo: "updateAt",
        bgColor: Colors.transparent,
        textColor: Colors.white,
      );
      return FutureBuilder(
          future: getLeaderBoards(0),
          builder:
              (BuildContext context, AsyncSnapshot<LeaderBoards> snapshot) {
            if (!snapshot.hasData) {
              return Center(
                child: CircularProgressIndicator(),
              );
            } else {
              return Builder(builder: (BuildContext context) {
                return Center(
                    child: new EasyRefresh(
                      key: _easyRefreshKey,
                      behavior: ScrollOverBehavior(),
                      refreshHeader: ConnectorHeader(
                        key: _connectorHeaderKey,
                        header: header,
                      ),
                      refreshFooter: ConnectorFooter(
                        key: _connectorFooterKey,
                        footer: footer,
                      ),
                      child: CustomScrollView(
                        semanticChildCount: str.length,
                        slivers: <Widget>[
                          SliverList(
                            delegate: SliverChildListDelegate(<Widget>[header]),
                          ),
                          SliverList(
                              delegate: SliverChildBuilderDelegate(
                                    (context, index) {
                                      return new Container(
                                          height: 70.0,
                                          child: Card(
                                            child: new Text(
                                              '${index+1}: ${str[index].userName}',
                                              style: new TextStyle(fontSize: 18.0),
                                            ),
                                          ));
                                },
                                childCount: str.length,
                              )),
                          SliverList(
                            delegate: SliverChildListDelegate(<Widget>[footer]),
                          )
                        ],
                      ),
                      onRefresh: () async {
                        await new Future.delayed(const Duration(seconds: 0), () {
                          setState(() {});
                        });
                      },
                      loadMore: () async {
                        getLeaderBoards(str.length).then((onValue) => {
                        updateLeaderBoardList(onValue)
                        });
                      },
  //                    loadMore: () async {
  //                      await new Future.delayed(const Duration(seconds: 0), () {
  //                        getLeaderBoards(str.length).then((onValue) => {
  //                              updateLeaderBoardList(onValue)
  //                        });
  //                      });
  //                    },
                    )
                );
              });
            }
          });
    }
  }



  LeaderBoards leaderBoardsFromJson(String str) {
    final jsonData = json.decode(str);
    return LeaderBoards.fromJson(jsonData);
  }

  String leaderBoardsToJson(LeaderBoards data) {
    final dyn = data.toJson();
    return json.encode(dyn);
  }

  class LeaderBoards {
    String boardType;
    List<Entry> entries;
    int totalEntries;

    LeaderBoards({
      this.boardType,
      this.entries,
      this.totalEntries,
    });

    factory LeaderBoards.fromJson(Map<String, dynamic> json) => new LeaderBoards(
      boardType: json["boardType"] == null ? null : json["boardType"],
      entries: json["entries"] == null ? null : new List<Entry>.from(json["entries"].map((x) => Entry.fromJson(x))),
      totalEntries: json["totalEntries"] == null ? null : json["totalEntries"],
    );

    Map<String, dynamic> toJson() => {
      "boardType": boardType == null ? null : boardType,
      "entries": entries == null ? null : new List<dynamic>.from(entries.map((x) => x.toJson())),
      "totalEntries": totalEntries == null ? null : totalEntries,
    };
  }

  class Entry {
    String userName;
    int eloRating;
    String profileIconId;
    String namePlateId;

    Entry({
      this.userName,
      this.eloRating,
      this.profileIconId,
      this.namePlateId,
    });

    factory Entry.fromJson(Map<String, dynamic> json) => new Entry(
      userName: json["userName"] == null ? null : json["userName"],
      eloRating: json["eloRating"] == null ? null : json["eloRating"],
      profileIconId: json["profileIconId"] == null ? null : json["profileIconId"],
      namePlateId: json["namePlateId"] == null ? null : json["namePlateId"],
    );

    Map<String, dynamic> toJson() => {
      "userName": userName == null ? null : userName,
      "eloRating": eloRating == null ? null : eloRating,
      "profileIconId": profileIconId == null ? null : profileIconId,
      "namePlateId": namePlateId == null ? null : namePlateId,
    };
  }
dart flutter
2个回答
0
投票

我看着documentation of loadMore。因为它说分配给loadMore的函数的主体应该是async,所以你不需要使用then

loadMore: () async {
     final result = await getLeaderBoards(str.length);
     updateLeaderboardList(result);
},

0
投票
loadMore: () async {
     await getLeaderBoards(str.length).then((onValue) => {
     updateLeaderboardList(onValue)
     });
},

但是“等待”我的加载器等待函数在完成动画之前完成。

© www.soinside.com 2019 - 2024. All rights reserved.