The ParentDataWidget Flexible(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject - flutter

I am trying to apply if condition on the result of a retrieving query from Firebase real-time database. What I am trying to do is to tell flutter if a specific field of the result is equal to what I specified then and only then show the result.
I am getting this error as a result of running my code:
Screenshot of the error message
and my code:
body: SingleChildScrollView(
child: Flexible(
flex: 1,
child: FirebaseAnimatedList(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
query: _dBRefAppt,
itemBuilder: (
BuildContext context,
DataSnapshot snapShot,
Animation<double> animation,
int index,
) {
if (snapShot.value['tutor_id'] == currentUId &&
snapShot.value['status'] == 'accepted') {
return new ListTile(
title: new Text(snapShot.value['date']),
subtitle: new Text(snapShot.value['time']),
);
} else {
return null;
}
},
),
),
),
The problem is when I remove the if condition, the code works and shows all the results. How can I show only the results that I want. Any help is very much appreciated!

Just remove this:
child: Flexible(
flex: 1,
Use Flexible and Expanded only inside Rows, Columns and Flex widgets. Keep the if statement, it's not causing the error.

Related

Flutter ListView with nested ListView throws RangeError for offscreen widgets

First time working in Flutter and not really a software wizard. I've built an app that connects to Firebase and retrieves a data structure as a Map (all after login). This works fine. However, the data is (kind of) a list of lists (or Map of Maps), etc. Basic structure is:
{
title1: {
item-A: {
0: line1,
1: line2,
2: line3,
},
item-B: {
0: line1,
1: line2,
2: line3,
}
},
title2: {
item-A: {
0: line1,
...
}
The schema can have more or fewer titles, items, and lines, but the structure is the same.
The code I've implemented gets the values from the database (Firebase Realtime Database) via FutureBuilder, formats the results, and displays them. Retrieving the results and the general display formatting works as intended, but I can only see one or two of the list widgets before a huge red box is displayed and I get the following error:
The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 1: 1
If I run a Hot Refresh or Hot Reload, or just reload the browser, I get a few more rows of Widgets and the error changes to the next index increment:
The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 4: 5
If I keep refreshing, eventually the whole list shows up and the error goes away. Obviously this is not the desired behavior, however. I've been working this and testing different approaches but I don't really understand what the issue is.
My code (with a couple of details left out) is as follows:
Widget build(BuildContext context) {
return Consumer<ApplicationState>(
builder: (context, appState, child) {
selectedIndex.add(-1);
return Scaffold(
...
body: FutureBuilder(
future: futureDataRetreiverFunction(),
builder: (BuildContext context, AsyncSnapshot<Map> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
... // convert the snapshot.data here //
return Container(
...
child: ListView(
shrinkWrap: true,
children: [
Form(
key: _formKey,
child: Column(
children: [
ListView.builder(
scrollDirection: Axis.vertical,
controller: ScrollController(),
shrinkWrap: true,
itemCount: snapshotData.keys.length, // the data is a Map
itemBuilder: (BuildContext context, int index) =>
Column(
children: [
...
Row(
children: [
Text(snapshotData.keys.elementAt(index)),
]
),
Row(
children: [
Text(selectedIndex[index].toString())
]
),
Row(
children: [
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 0, 10),
child: ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: snapshotData.values.elementAt(index)[1].length,
itemBuilder: (BuildContext context, int index2) =>
Text(snaptshotData.values.elementAt(index)[1][index2])
)
)
)]
)
])
)
])
])
);
...
Vishal pointed out the answer in his first comment to this question. I am using "selectedIndex" as part of a setState({}) call to change some visuals as part of an onTap: () {} call. I was initiating the list with a simple initiation call earlier in the class (List selectedIndex = [];), but then was only adding 1 item to the index in the builder. However, in this case, there are a total of 6 items which get built (more/less in other scenarios), and that was throwing the index error. Which is why it would increment on reload (another seletedIndex.add(-1); was called). I dropped in a quick function to pre-populate the index based on the size of the snapshot data, along the lines of:
for (var counter=0; counter<snapshotData.keys.length; counter++) {
selectedIndex.add(-1);
}
This solved the index RangeError.

How to disable Listview Stretching on overscrolling

I don't know if stretching is the correct word to describe it.
But it looks like this.
"last message 👋👋" is the last message in this convo and the empty space below is the 'stretching'. Once I release the touch from my screen it goes back to normal. I want to disable that 'stretching' so that nothing happens when the user overscrolls.
ListView code:
ListView.builder(
controller: _controller1,
physics: BouncingScrollPhysics(),
itemCount: snapshot.data!.docs.length, //snapshot from parent StreamBuilder
itemBuilder: (context, index) {
final allowedOrNot = index == 0
? true
: compareDate( // Userdefined function to check if the dates above messages should be displayed or not
currentSnap: snapshot.data!.docs[index]
.data()['serverTimeStamp'],
previousSnap: snapshot.data!.docs[index - 1]
.data()['serverTimeStamp']);
return Column(
children: [
allowedOrNot
? chatDater( // the date widget (above some messages to indicate the date of conversation)
data: dataForChatDater( // Userdefined function which returns Strings like 'Yesterday', 'Today' for the widget to display
snap: snapshot.data!.docs[index]
.data()['serverTimeStamp']),
)
: const SizedBox(
width: 0,
height: 0,
),
Align(
alignment:
snapshot.data!.docs[index].data()['sender'] ==
widget.usernameOfFriend
? Alignment.centerLeft
: Alignment.centerRight,
child: MessageBubble( // The ChatBubble widget used to display the messages
timestamp: snapshot.data!.docs[index]
.data()['serverTimeStamp'],
message: snapshot.data!.docs[index].data()['message'],
IsYou: snapshot.data!.docs[index].data()['sender'] ==
widget.usernameOfFriend
? false
: true,
),
),
],
);
},
),
It is natural behavior of BouncingScrollPhysics.
If you don't want to overscroll, you can change it to NeverScrollableScrollPhysics.
Try shrinkWrap:true in your ListView.builder and mainAxisSize:MainAxisSize.min in Column as follows:
ListView.builder(
//other
shrinkWrap: true,
itemBuilder: (context, index) {
return Column(
mainAxisSize: MainAxisSize.min, //use this
children: [
//your children
],
);
})

Flutter. Multiple heroes share same tag. ListView with buttons

Can't figure it out how to solve this problem. So, here is the simplest code which represents my problem:
Scaffold(
body: Stack(
children: <Widget>[
...
Scrollbar(
child: ListView.builder(
primary: false,
shrinkWrap: true,
itemCount: _mapBloc?.mapData?.companies?.count ?? 0,
itemBuilder: (context, index) {
final company = _mapBloc?.mapData?.companies?.data[index];
return InkWell(
child: Hero(
tag: company.id,
child: Card(
child: Container(
height: 50,
width: double.infinity,
),
),
),
onTap: () {
Navigator.of(context)
.pushNamed('/company', arguments: company)
.then(
(results) {
if (results is PopWithResults) {
PopWithResults popResult = results;
}
},
);
},
);
},
),
)
],
),
);
And stack trace:
The following assertion was thrown during a scheduler callback:
There are multiple heroes that share the same tag within a subtree.
Within each subtree for which heroes are to be animated (i.e. a PageRoute subtree), each Hero must
have a unique non-null tag.
...
The items count in ListView changes with every database request. If the size is up to 5 widgets in ListView, then clicking works correctly, as soon as the list expands to, for example, 8 elements, I get the error written above. With what it can be connected? I tried to use unique Hero tags, but this does not solve the problem.
I need some advice and hope you can help me. If you need more information, please, write the comment.
Thanks for your attention!

RangeError (index): Invalid value: Not in range 0..1, inclusive: 2. How can this be fixed?

I am building a static ListView. How can I solve this error? Also how can I add a UI to the ListView?
Following is my class MatchData code:
class MatchData {
String date, team1, team2, time;
MatchData({#required this.date, #required this.team1, #required this.team2, #required this.time});
}
Following is the Data I want to show in the ListView:
final List<MatchData> dayMatch = [
MatchData(
date: '12/02/2020',
team1: 'Mumbai Indians',
team2: 'Bangalore',
time: '16:00'),
MatchData(
date: '12/02/2020',
team1: 'Mumbai Indians',
team2: 'Bangalore',
time: '16:00')
];
match() {
return dayMatch;
}
Following is the body of my Widget:
body: Center(child: ListView.builder(itemBuilder: (context, index) {
return Card(
child: Row(
children: <Widget>[
Text(dayMatch[index].date),
Text(dayMatch[index].team1),
Text(dayMatch[index].time),
Text(dayMatch[index].team2),
],
),
);
}
If you don't specify itemCount and the screen is big enough to display ten items, ListView.builder() builds a little more than ten children, and even more on demand if you scroll down.
In your case, ListView.builder() tries to build more than two children, while your list (dayMatch) only has two elements, which is why the error occurs.
To fix it, just pass the number of items to the itemCount argument, or it'll be somewhat better to use the default constructor of ListView instead if the number is fixed and small. ListView.builder() does more computing under the hood to be flexible, which is a little too much for a small list.
You can use "itemCount".
child: ListView.builder(
itemCount: dayMatch.length,
itemBuilder: (context, index) {
return Card(
child: Row(
children: <Widget>[
Text(dayMatch[index].date),
Text(dayMatch[index].team1),
Text(dayMatch[index].time),
Text(dayMatch[index].team2),
],
),
);
},
),

ListView inside Column throws error 'Vertical viewport was given unbounded height'

My question seems to be a duplicate of ListView inside Column causes 'Vertical viewport was given unbounded height' but the solution to add an Expanded or Flexible widget around the ListView doesn't work at all. It still throws the same error: Vertical viewport was given unbounded height.
var data = ['a','b','c','d'];
Column(
children: <Widget>[
ListView.builder(
itemCount: data.length,
itemBuilder: (ctx, i) {
return Row(
children: <Widget>[
Text(data[i], style: TextStyle(fontSize: 24 * Rat.rat, color: Colors.white)),
],
);
},
),
],
);
Obviously it can easily be fixed by adding a container around the ListView with a fixed height but there should be no need for that, I want it to be dynamically sized.
UPDATE:
Try something like this:
class Esempio1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("WAKAWAKA"),
),
body: Container(
child: Column(
children: <Widget>[
Text("eg1"),
Text("eg2"),
Text("eg3"),
Expanded(
child: ListView.builder(
itemCount: 20,
itemBuilder: (ctx,i){
return ListTile(title: Text("aaaaaa$i"),);
},
),
)
],
),
),
);
}
}
I just tried this code and it should do what you want.
The OP actually had the block of code posted contained inside another Column, that's why the Expanded wasn't working as it should when wrapped around the ListView. Wrapping the Column inside another Expanded solved the problem and made it all work as expected.
How about wrapping ListView builder in SingleChildScrollView and setting up its physics to
physics: NeverScrollableScrollPhysics(),