3
votes

I have this news ApI, which gets latest news updates but my listview gives me an error even when i have an item "itemCount" to its length.

i tried "_total.length" on the Itemcount but it gives me an error.. which says "The getter 'length' isn't defined for the class 'int'.

Try importing the library that defines 'length', correcting the name to the name of an existing getter, or defining a getter or field named 'length'".

class _NewsUpdateState extends State<NewsUpdate> {

  List _bottomItems = 
   [
    {"icon": FontAwesomeIcons.fire, "index": 0},
    {"icon": FontAwesomeIcons.moneyBillAlt, "index": 1},
    {"icon": FontAwesomeIcons.bell, "index": 2},
    {"icon": FontAwesomeIcons.futbol, "index": 3},
  ];

  String _apiKey = '46d80623786da4a97847da2b6cd7747';

  int _currentTab = 0;
  String _apiUrl = '';
  int _total = 0;
  List _articles = [];
  bool _loading = true;

  @override
  void initState() {
    super.initState();

    changeTab(index: 0);
  }

  void changeTab({int index = 0}) {
    //tab1 is about top-headlines
    //tab2 is about bitcoins
    //tab3 = apple
    //tab4 = techcrunch

    switch (index) {
      case 0:
        _apiUrl =
            'https://newsapi.org/v2/top-headlines?country=za&apiKey=' +
                _apiKey;
        break;
      case 1:
        _apiUrl =
            'https://newsapi.org/v2/top-headlines?country=za&category=business&apiKey=' +
                _apiKey;
        break;
      case 2:
        _apiUrl =
            'https://newsapi.org/v2/top-headlines?country=za&category=entertainment&apiKey=' +
                _apiKey;
        break;
      case 3:
        _apiUrl =
            'https://newsapi.org/v2/top-headlines?country=za&category=sports&apiKey=' +
                _apiKey;
        break;
    }

    print(_apiUrl);

    setState(() {
      _loading = true;
      _total = 0;
      _articles = [];
    });

    http.get(_apiUrl).then((response) {
      var data = json.decode(response.body);
      setState(() {
        _total = data['totalResults'];
        _articles = data['articles'];
        _loading = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          "Latest News",
          style: TextStyle(
              color: Colors.black, fontSize: 25.0, fontWeight: FontWeight.bold),
        ),
        elevation: 5.0,
        backgroundColor: Colors.white,
        centerTitle: true,
      ),
      bottomNavigationBar: _buildBottomNavigation(context),
      body: new SafeArea(child: _buildBody(context)),
    );
  }

  _buildBottomNavigation(BuildContext context) {
    var _items = <BottomNavigationBarItem>[];

    for (var item in _bottomItems) {
      _items.add(new BottomNavigationBarItem(
        icon: new Icon(
          item['icon'],
          color: Colors.black,
        ),
        title: new Text(''),
      ));
    }

    return new BottomAppBar(
      color: Colors.white,
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: _bottomItems.map((x) {
          return new IconButton(
            icon: new Icon(
              x['icon'],
              color: _currentTab == x['index'] ? Colors.black : Colors.black38,
            ),
            onPressed: () {
              setState(() {
                _currentTab = x['index'];
              });
              changeTab(index: x['index']);
            },
          );
        }).toList(),
      ),
    );
  }

  _buildBody(BuildContext context) {
    if (_loading) {
      return new SpinKitCircle(
        color: Colors.black,
        size: 50.0,
      );
    }

    print(_articles);

    return new ListView.builder(
      itemBuilder: (context, int index) {
        return new Padding(
          padding: new EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
          child: new ListItem(data: _articles[index]),
        );
      },
      itemCount: _total,
    );
  }
}

This should set the actual length of the total result from the api to the itemcount

2

2 Answers

7
votes

I had the same issue:

you have to also pass the itemCount parameter

child: ListView.builder(
    itemCount: list.length,
    itemBuilder: (context, index) {
        return Text(list[index].description);
    }),
0
votes

The number 'totalResults' is bigger then the number of articles actually got in the request, therefor your setState should look like this:

setState(() {
        _total = data['articles'].length;
        _articles = data['articles'];
        _loading = false;
      });

You can use the page and pageSize parameters to get more articles from the api. Take a look at their documentaion on https://newsapi.org/docs/endpoints/top-headlines.