flutterflutter-layout

How to fill SliverList with API data


I'm building a weather forecast app in which SliverAppBar shows current weather and SliverList shows daily forecast in form of cards. I get data from DarkSky API as a Map.

I have completed the current weather part with FutureBuilder, but now I'm having a trouble finding how to fill SliverList. I tried to do it with FutureBuilder as well, but without success.

This is my code

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(

        body: new CustomScrollView(
          slivers: <Widget>[
            new SliverAppBar(
              brightness: Brightness.dark,
              centerTitle: true,
              title: Text('Weather'),
              expandedHeight: 300,
              floating: true,
              pinned: true,
              snap: true,
              flexibleSpace: FlexibleSpaceBar(
                  background: new Container(
                child: updateCurrentWeather(), //METHOD CONSTRUCTING CONTENT OF SliverAppBar
              )),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate(
                  (context, index) => Card(
                        margin: EdgeInsets.fromLTRB(30, 3, 30, 3),
                        color: Colors.black12,
                        child: new ListTile(
                          leading: Icon(Icons.watch_later),
                          title: new Text('$index',
                              style: new TextStyle(color: Colors.white)),
                          subtitle: new Text('29 °C'),
                        ),
                      ),
                  childCount: 20),
            )
          ],
        ));
  }

  Future<Map> getWeather(String key, double lat, double lon) async {
    String apiUrl =
        'https://api.darksky.net/forecast/$key/$lat,$lon?lang=sk&units=si';
    http.Response response = await http.get(apiUrl);
    return json.decode(response.body);
  }

How can I fill the SliverList with the map I get?


Solution

  • You can use this code but remember to create your data model for the network response to fill the list:

    class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
    
    @override
    Widget build(BuildContext context) {
        return new Scaffold(
    
           body: new CustomScrollView(
              slivers: <Widget>[
              new SliverAppBar(
                brightness: Brightness.dark,
                centerTitle: true,
                title: Text('Weather'),
                expandedHeight: 300,
                floating: true,
                pinned: true,
                snap: true,
                flexibleSpace: FlexibleSpaceBar(
                    background: new Container(
                      child: updateCurrentWeather(), //METHOD CONSTRUCTING CONTENT OF SliverAppBar
                    )),
             ),
              FutureBuilder(
               future: getWeather(
                   "secret key", 37.8267, -122.4233),
               builder: (context, projectSnap) {
     //                Whether project = projectSnap.data[index]; //todo check your model
                 var childCount = 0;
                 if(projectSnap.connectionState !=
                     ConnectionState.done || projectSnap.hasData == null)
                   childCount  = 1;
                 else
                   childCount = projectSnap.data.length;
                 return SliverList(
                  delegate: SliverChildBuilderDelegate(
                          (context, index) {
                        if (projectSnap.connectionState !=
                            ConnectionState.done) { //todo handle state
                          return CircularProgressIndicator(); //todo set progress bar
                        }
                        if (projectSnap.hasData == null) {
                          return Container();
                        }
                        return Card(
                          margin: EdgeInsets.fromLTRB(30, 3, 30, 3),
                          color: Colors.black12,
                          child: new ListTile(
                            leading: Icon(Icons.watch_later),
                            title: new Text("$index",
                                style: new TextStyle(color: Colors.white)),
                            subtitle: new Text('29 °C'), //todo set your data from response
                          ),
                        );
                      },
                      childCount: childCount),
                );
              },
            ),
          ],
        ));
    }
    
    Future<Map> getWeather(String key, double lat, double lon) async {
     String apiUrl =
        'https://api.darksky.net/forecast/$key/$lat,$lon?lang=sk&units=si';
     http.Response response = await http.get(apiUrl);
     return json.decode(response.body);
    }
    
    }