StreamBuilder inside the ListviewBuilder not scrolling - flutter

Problem: I am beginner for flutter developing. I tried to get data from firestore and display it. But scrolling listview didn't respond to one finger so I had to use more than one. How to solve this problem.
body: StreamBuilder(
stream: _firebase_auth.collection("ContactData").snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemExtent: 100.0,
itemBuilder: (context, index) {
DocumentSnapshot data = snapshot.data.docs[index];
return Card(
child: ListView(padding: EdgeInsets.all(8.0), children: [
Text('sds'),
Text('sds'),
Text('sds'),
Text('sds'),
Text('sds'),
]),
);
});
} else {
return Text('Loading Data.....');
}
},
),

you should wrap streamBuilder with the SingleChild scroll view or use shrinkWrap: true,physics: ScrollPhysics(),
body: StreamBuilder(
stream: _firebase_auth.collection("ContactData").snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: snapshot.data.docs.length,
itemExtent: 100.0,
itemBuilder: (context, index) {
DocumentSnapshot data = snapshot.data.docs[index];
return Card(
child: ListView(padding: EdgeInsets.all(8.0), children: [
Text('sds'),
Text('sds'),
Text('sds'),
Text('sds'),
Text('sds'),
]),
);
});
} else {
return Text('Loading Data.....');
}
},
),

add this line in listView.builder
physics: AlwaysScrollableScrollPhysics(),

Wrap stream builder with SingleChildScrolView.
This will make the screen a scrollable element.
Set physics of ListView.builder to NeverScrollablePhysics.
This will prevent the scrolling of the parent ListView.Builder, but it's okay because it's parent, SingleChildScrollView is
scrollable.
Set physics of ListView to Scrollable
If you want to, not sure if you want to scroll these items or just display.

Related

Flutter - unboundedHeight error within ListView

Flutter newbie here!
Currently, my Scaffold has 2 listview builders and the bottom one is giving me the unbounded height (!constraints.hasBoundedHeight error) issue.
I have tried using shrinkWrap on all 3 list views, as suggested in similar questions but I get the same error.
The only thing that works is wrapping the FutureBuilder in a SizedBox. But that seems unintuitive to me, as I would want it to ideally expand as needed and be scrollable.
My rough solution is to maybe dynamically calculate the height based on the number of items the FutureBuilder needs, but again, I feel there should be a better solution.
My code snippet is attached below:
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
itemBuilder: (context, index) {
return const SuggestCard(
indexKey: 'takt',
);
}),
FutureBuilder<AnimeDetails>(
future: _animeDetail,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 2, //Number of anime from list
itemBuilder: (context, index) {
var anime = snapshot.data; //Get the data from the index
return AnimeCard(
anime: anime,
);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
],
),
);
As per your comment I think below link will helpful to you.
Lists
The parent ListView handling scroll event for body and while second ListView will have fixed height, you can do it like this
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => ListView(
children: [
SizedBox(
height: constraints.maxHeight * .3,
child: ListView.builder(
itemCount: 122,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Text("H $index"),
),
),
ListView.builder(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(), // parent controll the scroll event
itemCount: 44,
itemBuilder: (context, index) => Text("$index"),
),
],
),
));
I just added the below lines to your code. You can try the below code.
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const SuggestCard(
indexKey: 'takt',
);
}),
FutureBuilder<AnimeDetails>(
future: _animeDetail,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 2, //Number of anime from list
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
var anime = snapshot.data; //Get the data from the index
return AnimeCard(
anime: anime,
);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
],
),
);

Join two ListViews

I want to create a ToDo-App that saves the ToDo's in Firestore.
I am already able to add every new ToDo Item to Firestore and now I want those Items that were added to pop up when the application opens.
I have made the following:
body: Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return Expanded(
child: _buildList(snapshot.requireData),
);
},
),
Expanded(
child:ListView(
children: _getItems(),
),
),
],
),
Here the method to build the List with all the stored ToDo's:
Widget _buildList(QuerySnapshot snapshot){
return ListView.builder(
itemCount: snapshot.docs.length,
itemBuilder: (context,index){
final doc=snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}
(The function _buildTodoItem simply returns a List Tile)
This creates two ListViews (one of the first half of the screen and the other one on the other). Is there any possible way to unify both?
Wrap your column with SingleChildScrollView and put physics: NeverScrollableScrollPhysics(). This will merge the scroll of both of your lists.
body: SingleChildScrollView(
child :Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return _buildList(snapshot.requireData);
},
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: _getItems(),
),
],
),),
Widget _buildList(QuerySnapshot snapshot) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.docs.length,
itemBuilder: (context, index) {
final doc = snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}

Fix Renderbox Error with Horizontal Listview

I am trying to change my ListView to be Shown horizontally instead of veritcally by default. However, when I have done this, I face the following an error. The error occurs at both the Widgets returned by the _buildListItem function and disappears when the scrolldirection is changed from vertical back to horizontal.
RenderBox was not laid out: RenderPointerListener#98473 relayoutBoundary=up5 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
The code of the ListView Builder is
Widget _buildListItem (BuildContext context,DocumentSnapshot doc,int index)
{
if(index ==0)
{
return ListTile(title:Container( height:200,width: 100,child: Card(shape: new RoundedRectangleBorder(),child:Column(children:<Widget>[new Flexible(child:Text(widget.prayerName,style: TextStyle(fontSize: 32,fontWeight: FontWeight.bold))),Text(widget.blurb,style: TextStyle(fontSize: 28))]))));
}
else {
return RaisedButton(child: Text("a"),);
}
}
Here is the body of my build widget where my list view is declared
body: StreamBuilder(
stream: Firestore.instance.collection('quranKhwani').document(widget.docID).collection("juz").orderBy("juzNumber").snapshots(),
builder: (context,snapshot)
{
if(!snapshot.hasData)return const Text("Loading..");
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context,index)=>
_buildListItem(context,snapshot.data.documents[index],index),
itemCount: snapshot.data.documents.length,
);
}
)
));
Container(
height: _height //add height
child: StreamBuilder(
builder: (context, snapshot) {
return ListView.builder(
itemBuilder: (context, index) {},
scrollDirection: Axis.horizontal,
);
},
),
)
You have to give height to the StreamBuilder like:
body: Container(
height: 300, // Height you want
child:
StreamBuilder(
stream: Firestore.instance.collection('quranKhwani').document(widget.docID).collection("juz").orderBy("juzNumber").snapshots(),
builder: (context,snapshot)
{
if(!snapshot.hasData)return const Text("Loading..");
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context,index)=>
_buildListItem(context,snapshot.data.documents[index],index),
itemCount: snapshot.data.documents.length,
);
}
),
),
),

ListView.builder inside futurebuilder inside Listview

I wanted to to make my home page scrollable i mean i want to scroll everthing on the body so i made a list view and inside the list view there are other widgets and under those widgets i want to show a future builder that has another listview.builder in it but i dont want it to be scrolled alone i want it to be scrolled with the other widgets in the home screen
this is my home screen body:
body: SafeArea(
child: ListView(
children: <Widget>[
Search(),
FeaturedProducts(),
OnSaleProducts(),
],
),
),
OnSaleProducts() is the widget that has a futurebuilder in it this is the code
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
child: FutureBuilder(
future: getOnSaleProduct(),
builder: (_, snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return ListView.builder(
itemCount: 4,
itemBuilder: (_, index) {
return Column(
);
});
}else return ListView.builder(
scrollDirection: Axis.vertical,
itemCount: 9,
itemBuilder: (_, index) {
return InkWell(child: ProductCard(name: "new", price: 123, picture: '', onSale: true));
});
}));
}
Then you should not use a ListView inside OnSalesProduct() but a simple Column!
Column(children: List.generate(count, (int index) => widget(index))
Hopefully, what you are trying to know:
Scroll everthing on the body
Inside the scrollable view, want to show a future builder that has
another listview.builder
Don't want it to be scrolled alone it to be scrolled with the other
widgets in the home screen
Let's try this code, hopefully you will get your answerers and solution together:
SingleChildScrollView(
child: Column(
children: <Widget>[
Search(),
FeaturedProducts(),
OnSaleProducts(),
],
),
),
Now do this for OnSaleProducts() widget:
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height, // better for fixed size
width: double.infinity,
child: FutureBuilder<PopularFoodList>(
future: getOnSaleProduct(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
scrollDirection: Axis.vertical,
itemCount: 9,
itemBuilder: (context, index) {
var item = snapshot.data[index]; // snapshot.data.anotherProperty[index]; // If your model has anotherProperty
return InkWell(child: ProductCard(name: item.name, price: item.price, picture: '', onSale: true));
});
} else if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
}
return Center(child: CircularProgressIndicator());
})
);
}

Having a different StreamBuilder for every tab in TabBarView

I am trying to create a home page that has 3 tabs: Friends, Groups and Events.
After finally managing to load events for the current user only, I realised ill have a hard time loading different data for each tab - as the StreamBuilder stream: will always be the same for all the tabs.
I need help finding a way to have a different StreamBuilder for each of my tabs.
Code below:
StreamBuilder(
stream: _streamer(),//Firestore.instance.collection("Events").snapshots(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return new SizedBox(
height: MediaQuery.of(context).size.height - 42 - MediaQuery.of(context).padding.bottom -AppBar().preferredSize.height - kToolbarHeight,
child: Column(
children: <Widget>[
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
Container(
child: ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (context, index) =>
_buildListItem(context,
snapshot.data[index]),
separatorBuilder: (context, index) {
return Divider();
},
shrinkWrap: true,
),
),
],
),
)
],
));
},
)
This is how the home page looks
I assume you're loading all data required for all your tabs using that stream. What you could do is have distinct pairs of stream/StreamBuilder for each tab:
... // widgets leading up to the TabBarView
TabBarView(
controller: _controller,
children: <Widget>[
StreamBuilder(
stream: friendsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return FriendsWidget();
}
),
StreamBuilder(
stream: groupsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return GroupsWidget();
}
),
//... etc
]
)
You could also wrap ONLY the widgets that should be rebuilt with a StreamBuilder instead of wrapping the whole parent widget:
... // widgets leading up to the TabBarView
TabBarView(
controller: _controller,
children: <Widget>[
Column(
children: <Widget>[
SomeWidget(),
AnotherWidget(),
StreamBuilder(
stream: friendsStream,
builder: (BuildContext context, AsyncSnapshot<SomeData> snapshot) {
return FriendsWidget();
}
)
]
),
// ... etc
]
)
If you are compelled to load all your data from the database at once, you could use a Repository class to load and store all your data, and then, depending on your architecture, have streams built from that class.
As a side note, I highly recommend using a Bloc with BlocBuilder. Blocs are just far superior to other designs (in most cases). flutter_bloc is my favorite.