首页 > 解决方案 > Flutter Streambuilder 到重复的数据表标题

问题描述

我正在尝试弄清楚如何将以下数据放入数据表中,但我真的很挣扎,因为它不断重复标题

import 'dart:async';
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class PlayerList extends StatefulWidget {
  @override
  _PlayerListState createState() => new _PlayerListState();
}

class _PlayerListState extends State<PlayerList> {
  StreamController<List<Map<String, dynamic>>> _postsController;
  final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
  List<Map<String, dynamic>> _list = List();
  ScrollController _scrollController = new ScrollController();

  int count = 0;
  var url = '';

  bool fetching = false, endReached = false;

  List data;

  Future<List<dynamic>> fetchPlayer() async {
    url =
        'https://supercoach.heraldsun.com.au/2020/api/afl/classic/v1/players-cf?embed=notes%2Codds%2Cplayer_stats%2Cpositions';
    final response = await http.get(url);
    if (response.statusCode == 200) {
      print('fetching player');
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load players');
    }
  }

  loadPlayers() async {
    fetchPlayer().then((res) async {
      res.forEach((model) => _list.add(model));
      _postsController.add(_list);
      return res;
    });
  }

  Future<Null> _handleRefresh() async {
    fetching = true;
    fetchPlayer().then((res) async {
      if (res != null) {
        res.forEach((model) => _list.add(model));
        _postsController.add(_list);
        if (res.length < 10) {
          endReached = true;
          _list.add(Map());
          _postsController.add(_list);
        }
      } else {
        _postsController.add(null);
      }
      fetching = false;
      return null;
    });
  }

  @override
  void initState() {
    _postsController = new StreamController();
    loadPlayers();
    _scrollController
      ..addListener(() {
        var triggerFetchMoreSize =
            0.9 * _scrollController.position.maxScrollExtent;

        if (_scrollController.position.pixels > triggerFetchMoreSize &&
            !fetching &&
            !endReached) {
          _handleRefresh();
        }
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        key: scaffoldKey,
        appBar: AppBar(
          title: Text('Exploring Players'),
        ),
        backgroundColor: Color.fromRGBO(246, 249, 255, 1),
        body: Column(children: <Widget>[
          Expanded(
            child: StreamBuilder(
              stream: _postsController.stream,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                print('Has error: ${snapshot.hasError}');
                print('Has data: ${snapshot.hasData}');
//                print('Snapshot Data ${snapshot.data}');
                print('Connection State ${snapshot.connectionState}');

                if (snapshot.hasError) {
                  return Text(snapshot.error);
                }

                if (snapshot.connectionState == ConnectionState.waiting ||
                    snapshot.hasData == false) {
                  return Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        CircularProgressIndicator(
                            valueColor: new AlwaysStoppedAnimation<Color>(
                                Colors.purple)),
                        // Loader Animation Widget
                        Padding(padding: const EdgeInsets.only(top: 20.0)),
                      ],
                    ),
                  );
                }

                if (snapshot.data == null || snapshot.data.length == 0) {
                  return Column(
                    children: <Widget>[
                      Center(child: Text("Unable to find any players"))
                    ],
                  );
                }

//                if (snapshot.hasData == false) {
//                  return Scaffold(
//                    backgroundColor: Colors.white,
//                    body: new Stack(
//                      fit: StackFit.expand,
//                      children: <Widget>[
//                        // Render the Title widget, loader and messages below each other
//                        new Column(
//                          mainAxisAlignment: MainAxisAlignment.start,
//                          children: <Widget>[
//                            Expanded(
//                              flex: 1,
//                              child: Column(
//                                mainAxisAlignment: MainAxisAlignment.center,
//                                children: <Widget>[
//                                  CircularProgressIndicator(
//                                      valueColor: AlwaysStoppedAnimation<Color>(
//                                          Colors.purple)),
//                                  // Loader Animation Widget
//                                  Padding(
//                                      padding:
//                                          const EdgeInsets.only(top: 20.0)),
//                                  Text("Finding players"),
//                                ],
//                              ),
//                            ),
//                          ],
//                        ),
//                      ],
//                    ),
//                  );
//                }

                if (snapshot.hasData) {
                  return Column(
                    children: <Widget>[
                      Expanded(
                        child: Scrollbar(
                          child: ListView.builder(
                              controller: _scrollController,
                              physics: const AlwaysScrollableScrollPhysics(),
                              itemCount: snapshot.data.length,
                              itemBuilder: (context, index) {
                                Map<String, dynamic> player =
                                    snapshot.data[index];
                                print(snapshot.data[index]);
                                return DataTable(columns: [
                                  DataColumn(label: Text('Photo')),
                                  DataColumn(label: Text('Player')),
                                  DataColumn(label: Text('Round Results')),
                                  DataColumn(label: Text('Played')),
                                  DataColumn(label: Text('Total Points')),
                                  DataColumn(label: Text('Avg')),
                                  DataColumn(label: Text('3 Rd Avg')),
                                  DataColumn(label: Text('5 Rd Avg')),
                                ], rows: [
                                  DataRow(cells: [
//                                  TableRow(children: [
                                    DataCell(Image.network(
                                        "https://s.afl.com.au/staticfile/AFL%20Tenant/AFL/Players/ChampIDImages/XLarge2020/${player['feed_id']}.png?i10c=img.resize(scale_height:0.2)",
                                        height: 54,
                                        width: 54,
                                        fit: BoxFit.fitWidth)),
                                    DataCell(Column(children: [
                                      Text(
                                          "${player['first_name']} ${player['last_name']}"),
                                      Text(
                                          "${player['positions'][0]['position']}"),
                                      Text(
                                          "${player['player_stats'][0]['price']}")
                                    ])),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['points']}")),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['total_games']}")),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['total_points']}")),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['avg']}")),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['avg3']}")),
                                    DataCell(Text(
                                        "${player['player_stats'][0]['avg5']}")),
                                  ])
                                ]);
                              }),
                        ),
                      ),
                    ],
                  );
                }

                if (!snapshot.hasData &&
                    snapshot.connectionState == ConnectionState.done) {
                  return Text('No Players');
                }

                if (snapshot.connectionState != ConnectionState.done) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }

                return Text('No Data');
              },
            ),
          )
        ]));
  }
}

标签: flutterdartdatatablesflutter-layout

解决方案


import 'dart:async';
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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,
      ),
      home: PlayerList(),
    );
  }
}

class PlayerList extends StatefulWidget {
  @override
  _PlayerListState createState() => _PlayerListState();
}

class _PlayerListState extends State<PlayerList> {
  StreamController<List<Player>> _postsController;
  final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  List<Player> _list = <Player>[];
  ScrollController _scrollController = ScrollController();

  int count = 0;
  var url = '';

  bool fetching = false, endReached = false;

  List data;

  Future<List<dynamic>> fetchPlayer() async {
    url =
        'https://supercoach.heraldsun.com.au/2020/api/afl/classic/v1/players-cf?embed=notes%2Codds%2Cplayer_stats%2Cpositions';
    final response = await http.get(url);
    if (response.statusCode == 200) {
      print('fetching player');
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load players');
    }
  }

  Future<void> loadPlayers() async {
    await fetchPlayer().then((res) async {
      for (var model in res) {
        _list.add(Player.fromMap(model));
      }
      _postsController.add(_list);
    });
  }

  Future<void> _handleRefresh() async {
    fetching = true;
    await fetchPlayer().then((res) async {
      if (res != null) {
        for (var model in res) {
          _list.add(Player.fromMap(model));
        }

        _postsController.add(_list);
        if (res.length < 10) {
          endReached = true;
          _postsController.add(_list);
        }
      } else {
        _postsController.add(null);
      }
      fetching = false;
    });
  }

  @override
  void initState() {
    _postsController = StreamController();
    loadPlayers();
    _scrollController
      ..addListener(() {
        var triggerFetchMoreSize =
            0.9 * _scrollController.position.maxScrollExtent;

        if (_scrollController.position.pixels > triggerFetchMoreSize &&
            !fetching &&
            !endReached) {
          _handleRefresh();
        }
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: scaffoldKey,
        appBar: AppBar(
          title: Text('Exploring Players'),
        ),
        backgroundColor: Color.fromRGBO(246, 249, 255, 1),
        body: StreamBuilder<List<Player>>(
          stream: _postsController.stream,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Text(snapshot.error);
            }

            if (snapshot.connectionState == ConnectionState.waiting ||
                snapshot.hasData == false) {
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    CircularProgressIndicator(
                        valueColor:
                            AlwaysStoppedAnimation<Color>(Colors.purple)),
                    // Loader Animation Widget
                    Padding(padding: const EdgeInsets.only(top: 20.0)),
                  ],
                ),
              );
            }

            if (snapshot.data == null || snapshot.data.length == 0) {
              return Column(
                children: <Widget>[
                  Center(child: Text("Unable to find any players"))
                ],
              );
            }

            if (snapshot.hasData) {
              return SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: SingleChildScrollView(
                  physics: ClampingScrollPhysics(),
                  scrollDirection: Axis.horizontal,
                  child: DataTable(
                    columns: [
                      DataColumn(label: Text('Photo')),
                      DataColumn(label: Text('Player')),
                      DataColumn(label: Text('Round Results')),
                      DataColumn(label: Text('Played')),
                      DataColumn(label: Text('Total Points')),
                      DataColumn(label: Text('Avg')),
                      DataColumn(label: Text('3 Rd Avg')),
                      DataColumn(label: Text('5 Rd Avg')),
                    ],
                    rows: snapshot.data
                        .map(
                          (player) => DataRow(cells: [
                            DataCell(Image.network(
                                "https://s.afl.com.au/staticfile/AFL%20Tenant/AFL/Players/ChampIDImages/XLarge2020/${player.feedId}.png?i10c=img.resize(scale_height:0.2)",
                                height: 54,
                                width: 54,
                                fit: BoxFit.fitWidth)),
                            DataCell(Column(
                              children: <Widget>[
                                Text('${player.firstName} ${player.lastName}'),
                                Text(player.position),
                                Text(player.price.toString()),
                              ],
                            )),
                            DataCell(
                              Text(player.points.toString()),
                            ),
                            DataCell(Text(player.totalGames.toString())),
                            DataCell(Text(player.totalPoints.toString())),
                            DataCell(Text(player.avg.toString())),
                            DataCell(Text(player.avg3.toString())),
                            DataCell(Text(player.avg5.toString())),
                          ]),
                        )
                        .toList(),
                  ),
                ),
              );
            }

            if (!snapshot.hasData &&
                snapshot.connectionState == ConnectionState.done) {
              return Text('No Players');
            }

            if (snapshot.connectionState != ConnectionState.done) {
              return Center(
                child: CircularProgressIndicator(),
              );
            }

            return Text('No Data');
          },
        ));
  }
}

class Player {
  final String firstName;
  final String lastName;
  final String position;
  final int price;
  final int points;
  final String feedId;
  final int totalGames;
  final int totalPoints;
  final num avg;
  final num avg3;
  final num avg5;

  Player({
    @required this.firstName,
    @required this.lastName,
    @required this.position,
    @required this.price,
    @required this.points,
    @required this.feedId,
    @required this.totalGames,
    @required this.totalPoints,
    @required this.avg,
    @required this.avg3,
    @required this.avg5,
  });

  factory Player.fromMap(Map<String, dynamic> player) {
    return Player(
      avg: player['player_stats'][0]['avg'],
      avg3: player['player_stats'][0]['avg3'],
      avg5: player['player_stats'][0]['avg5'],
      feedId: player['feed_id'],
      firstName: player['first_name'],
      lastName: player['last_name'],
      points: player['player_stats'][0]['points'],
      position: player['positions'][0]['position'],
      price: player['player_stats'][0]['price'],
      totalGames: player['player_stats'][0]['total_games'],
      totalPoints: player['player_stats'][0]['total_points'],
    );
  }
}

推荐阅读