簡體   English   中英

如何在 Flutter 中執行分頁

[英]How to perform Pagination in Flutter

我一直在閱讀有關顫振分頁的各種文章,但似乎沒有一篇適合我。 我正在使用的 API 端點看起來像這樣http://camx.heropp.com/api/connect?offset=0 (這是一個示例鏈接,因此它不起作用)請求看起來像這樣

{
    "result": {
        "connectUsers": [
            {
                "_id": "5f6a412d2ea9350017bec99f",
                "userProfile": {
                    "rep_points": 0.75,
                    "visits": 0,
                    "bio": "Nothing for you ",
                    "gender": "Male",
                    "university": "University Of Technology",
                    "avatar": "https://camx.heroapp.com/5f6a412d2ea9350017bec99f"
                },
                "name": "Joseph Henshaw ",
                "userTag": "bigjo",
                "id": "5f6a412d2ea9350017bec99f",
                "sameCampus": true
            },
            {
                "_id": "5f6bbf1cbd5faa00170d92b1",
                "userProfile": {
                    "rep_points": 0,
                    "visits": 0
                },
                "name": "John Doe",
                "userTag": "@doee",
                "id": "5f6bbf1cbd5faa00170d92b1",
                "sameCampus": false
            }
        ]
    }
}

我想要實現的是對來自 api 的數據進行分頁..偏移量從 0 開始並隨着 10 增加,即獲得更多數據 0ffset=20..30.. 等等

這是我為了獲得上面顯示的 JSON 響應而發出的請求

Future<void> fetchConnect() async {
    var uri = Uri.parse('http://campusx.herokuapp.com/api/v1/users/connect');
    uri = uri.replace(query: 'offset=$offsetNumber');
    print(uri);
    try {
      final response = await http.get(
        uri,
        headers: {
          HttpHeaders.authorizationHeader: "Bearer $userToken",
        },

      );
      // List<Photo> fetchedPhotos = Photo.parseList(json.decode(response.body));
      if (response.statusCode == 200 || response.statusCode == 201) {
         print("IT works")
      } else {
        print(response.statusCode);
      }
      List<ConnectUsers> fetchedConnects =
          ConnectUsers.parseList(json.decode(response.body));
      setState(() {
        connectMore = fetchedConnects.length == defaultConnectsPerPageCount;
        loading = false;
        offsetNumber = offsetNumber + 10;
        connects.addAll(fetchedConnects);
      });
    } catch (e) {
      setState(() {
        loading = false;
        error = true;
      });
    }
  }

這就是我用於顯示數據的 UI 獲取方式(小部件 getConnect 放置在我的 Scaffold 主體中

 Widget getConnects() {
    if (connects.isEmpty) {
      if (loading) {
        return Center(
            child: Padding(
          padding: const EdgeInsets.all(8),
          child: CircularProgressIndicator(),
        ));
      } else if (error) {
        return Center(
            child: InkWell(
          onTap: () {
            setState(() {
              loading = true;
              error = false;
              fetchConnects();
            });
          },
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Text("Error while loading connects, tap to try again"),
          ),
        ));
      }
    } else {
      return ListView.builder(
          itemCount: connects.length + (connectMore ? 10 : 0),
          itemBuilder: (context, index) {
            if (index == connects.length - nextPageThreshold) {
              fetchConnects();
            }
            if (index == connects.length) {
              if (error) {
                return Center(
                    child: InkWell(
                  onTap: () {
                    setState(() {
                      loading = true;
                      error = false;
                      fetchConnects();
                    });
                  },
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child:
                        Text("Error while loading connects, tap to try agin"),
                  ),
                ));
              } else {
                return Center(
                    child: Padding(
                  padding: const EdgeInsets.all(8),
                  child: CircularProgressIndicator(),
                ));
              }
            }
            // final Photo photo = photos[index];
            final ConnectUsers connect = connects[index];
            return Card(
              child: Column(
                children: <Widget>[
                  // Image.network(
                  //   connect.name.connectUsers[index].userProfile.avatar,
                  //   fit: BoxFit.fitWidth,
                  //   width: double.infinity,
                  //   height: 160,
                  // ),
                  Padding(
                    padding: const EdgeInsets.all(16),
                    child: Text(connect.name,
                        // connect
                        // .result.connectUsers[index].userProfile.university,
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16)),
                  ),
                ],
              ),
            );
          });
    }
    return Container();
  }

這是我在使用此代碼時遇到的錯誤

The getter 'isEmpty' was called on null.
Receiver: null
Tried calling: isEmpty

看起來您正在小部件中調用connects.isEmpty,但您沒有初始化connects -> connected 為空,因此您會收到上述錯誤。 您可以進行空檢查或初始化連接

...
// initialise so connects is not null
connects = []
...
 Widget getConnects() {
    if (connects.isEmpty) {
      if (loading) {
        return Center(
(...)
 Widget getConnects() {
// do a null check before calling member
    if (connects == null || connects.isEmpty) {
      if (loading) {
        return Center(
(...)

我已經解決了這個問題,這是我使用的方式

這是我的 model.dart 課


import 'package:flutter/foundation.dart';

ConnectModel payloadFromJson(String str) =>
    ConnectModel.fromJson(json.decode(str));

String payloadToJson(ConnectModel data) => json.encode(data.toJson());

class ConnectModel {
  ConnectModel({
    this.result,
  });

  Result result;

  factory ConnectModel.fromJson(Map<String, dynamic> json) => ConnectModel(
        result: Result.fromJson(json["result"]),
      );

  Map<String, dynamic> toJson() => {
        "result": result.toJson(),
      };
}

class Result {
  Result({
    this.connect,
  });

  List<Connect> connect;

  factory Result.fromJson(Map<String, dynamic> json) => Result(
        connect: List<Connect>.from(
            json["connectUsers"].map((x) => Connect.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "connectUsers": List<dynamic>.from(connect.map((x) => x.toJson())),
      };
}

class Connect with ChangeNotifier {
  Connect({
    this.id,
    this.name,
    this.userTag,
    this.university,
    this.checkIsFollowing,
    this.avatar,
  });
  String name;
  String userTag;
  String id;
  String university;
  String avatar;
  bool checkIsFollowing;

  factory Connect.fromJson(Map<String, dynamic> json) => Connect(
        id: json["_id"],
        name: json["name"],
        userTag: json["userTag"],
        university: json["userProfile"]["university"],
        checkIsFollowing: json["checkIsFollowing"],
        avatar: json["userProfile"]["avatar"],
      );

  Map<String, dynamic> toJson() => {
        "_id": id,
        "name": name,
        "userTag": userTag,
        "userProfile"
            "university": university,
        "userProfile"
            "avatar": avatar,
        "checkIsFollowing": checkIsFollowing
      };
}

這是我的方法,其中 offsetNumber 默認初始化為 0

  List<Connect> mainList = [];
  List<String> nameList = [];
  Future<List<Connect>> getConnectionsList(var offsetNumber) async {
    var uri = "http://campusx.herokuapp.com/api/v1/users/connect?$offsetNumber";
    var token = "pass_your_token_here";
    try {
      final response =
          await http.get(uri, headers: {"Authorization": "Bearer $token"});
      if (response.statusCode == 200) {
        var data = json.decode(response.body);
        var d = data['result']['connectUsers'];
        for (var u in d) {
          Connect c = Connect.fromJson(u);
          mainList.add(c);
        }
        setState(() {
          nameList = mainList.map((e) => e.name).toList();
          //add other parameters gotten from the endpoint here, i used name only for test purposes
        });
      } else {
        print(response.body);
      }
    } catch (e) {
      print(e);
    }
    return mainList;
  }

這是我在其中顯示名稱的 ListView 構建器

     ListView.builder(
          itemCount: mainList.length,
          itemBuilder: (_, index) {
            return Container(
              height: 120,
              child: Text(
                nameList[index],
                style: TextStyle(fontSize: 39),
               ),
            );
          },
       )

然后 onClick 或按鈕,或者當列表到達手機屏幕底部時,您將 setState (() {}); 並增加 offsetNumber 的大小。 像這樣的東西:

setState(() {
  offsetNumber = offsetNumber + 10;
  future = getConnectionsList(offsetNumber);
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM