Kartabya Aryal
Kartabya Aryal

Reputation: 38

Can I define a ListView Builder with itemCount that isn't declared initially

The title must've been confusing. I actually don't know how to exactly describe it. However, I'll try my best to do so with the code sample:

So, I am trying to display a list of card under an expansion tile. The items to be displayed on these cards are dynamic and differ between expansion tiles. To do so I've used the property 'onExpansionChanged'. On this property I've written the following code:

onExpansionChanged: (value) {
  if (rearrangedDays[index] == 'Saturday' || rearrangedDays[index] == 'Sunday') {
    hour = ratesData.firstHourWeekend;
    print(ratesData.ratesWeekend);
    rates = ratesData.ratesWeekend;
    print(rates);
  } else {
    hour = ratesData.firstHourWeekday;
    print(ratesData.ratesWeekday);
    rates = ratesData.ratesWeekday;
    print(rates);                        
  }
}

And under the ListView Builder inside the child property of the ExpansionTile I have:

ListView.builder(
  shrinkWrap: true,
  itemCount: rates.length,
  itemBuilder: (context, index) {
    return Card(
      child: Container(
        alignment: Alignment.center,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: <Widget>[
              Text((hour++).toString() + ':00'),
              SizedBox(height: 10.0),
              Text(
                'Rs. ' + rates[index],
                style: TextStyle(fontFamily:'silka'),
              ),
            ],
          ),
        ),
      ),
    );
  },
),

Now the problem is, if I just declare an array, the item count will show an error saying it returned null. If I don't declare it initially and do it inside expansion changed, the rates variable in item count gives an error saying there's no such variable declared. As a workaround I've been initializing the array to a few empty elements.

List<String> rates = ['', '', '', '', '', '', '', '', '','','','','',''];

This way itemCount isn't null and the elements that I copy into the array in 'onExpansionChanged' is shown in the cards. This doesn't look like the right way. Plus if I were to display lesser or more elements than the number of empty elements I've initialized into the array, it gives me a range error.

I know this might be unclear. I really need this fixed so I'm ready to answer any extra details that you might need to help me debug this.

UPDATE: I added setState to make the changes and added a conditional operator before Container. It worked but had some side effects. Now the ListView Builder keeps building infinite ExpansionTiles.

return ExpansionTile(
 onExpansionChanged: (value) {
  setState(() {
   rates = ratesData.ratesWeekend;
  });

  setState(() {
   rates = ratesData.ratesWeekday;
  });
 },
 children:<widget>[
  ListView.builder(
   shrinkWrap: true,
   itemCount: rates.length,
   itemBuilder: (context, index) {
    return Card(
     child: Container(
      alignment: Alignment.center,
      child: Padding(
       padding: const EdgeInsets.all(8.0),
       child: Column(
        children: <Widget>[
         Text((hour++).toString() + ':00'),
         SizedBox(height: 10.0),
         Text(
          'Rs. ' + rates[index],
           style: TextStyle(fontFamily:'silka'),
          ),
         ],
        ),
       ),
      ),
    );
  },
),
]
);

Upvotes: 1

Views: 4316

Answers (1)

mjhansen3
mjhansen3

Reputation: 993

First of all, check if the rates array is null before setting the itemCount value

itemCount: rates == null ? 0 : rates.length,

this will set the itemCount to zero when the array returns null and hence will not display any item on the screen. This should solve your issue.

[UPDATE]
So actually just stick to your original onExpansionChanged function and add the setState() to each condition. I believe this should work.

onExpansionChanged: (value) {
  if (rearrangedDays[index] == 'Saturday' || rearrangedDays[index] == 'Sunday') {
    hour = ratesData.firstHourWeekend;
    print(ratesData.ratesWeekend);
    setState(() { // add your setState() this way
      rates = ratesData.ratesWeekend;
    });
    print(rates);
  } else {
    hour = ratesData.firstHourWeekday;
    print(ratesData.ratesWeekday);
    setState(() { // add your second setState() this way
      rates = ratesData.ratesWeekday;
    });
    print(rates);                        
  }
}

Upvotes: 2

Related Questions