I'm using ListView.separated() inside in the builder of showModalBottomSheet(). I would like for the BottomSheet to resize based on the number of ListTile widgets displayed.
Here's my code:
showModalBottomSheet(
context: context,
backgroundColor: Colors.blueGrey,
isScrollControlled: false,
builder: (context) => Wrap(
children: [
ListView.separated(
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) =>
ListTile(
title: Text(lists[index].listName),
),
separatorBuilder: (BuildContext context, int index) =>
Divider(),
),
],
),
);
I've tried wrapping the ListView inside a Wrap widget, but I got an error because the child of Wrap doesn't have a set height. Any tips?
You can do this by using the shrinkWrap parameter in the ListView widget.
showModalBottomSheet(
context: context,
builder: (context) => ListView.separated(
shrinkWrap: true,
itemCount: 4,
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text('item $index'),
),
separatorBuilder: (BuildContext context, int index) => Divider(),
),
);
Related
I have this code:
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => addProductClass()),
);
},
child: const Icon(
Icons.add,
color: Colors.black,
),
),
body: Column(children: [
FutureBuilder(
future: getDocId(),
builder: (context, snapshot) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: dataIDs.length,
itemBuilder: (BuildContext context, int index) {
return GetProduct(
documentId: dataIDs[index],
);
},
);
}),
Text("text")
]));
}
And i want to use scrollDirection: Axis.horizontal for listview. When I insert this value, I got the error:
Horizontal viewport was given unbounded height
Viewports expand in the cross axis to fill their container and '
'constrain their children to match their extent in the cross axis. '
'In this case, a horizontal viewport was given an unlimited amount of '
'vertical space in which to expand
How can I resolve this?
Easiest way is to provide a fixed height, either using a SizedBox or a ConstrainedBox with a maxHeight set.
Try to set shrinkwrap to true for listview builder
here is an example of listview builder in horizontal mode :
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (BuildContext context, int index){
return Container( margin: EdgeInsets.all(5), height:10, width:20, color:black);
}
),
),
hope it will help !
body: ListView.builder(
// i do not know where should i put the sizedBox to make these image has space to separate
itemCount: a.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ListTile(title: (a[index][0])),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => a[index][1]));
},
);
},
),
Use the ListView.separated, it has a separatorBuilder property that will help you to add the SizedBox, here the example:
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.separated(
itemCount: 10, // add the length of the array of items, for example data.length
itemBuilder: (BuildContext context, int index) => Text('Hola $index'), // here build the cards body
separatorBuilder: (BuildContext context, int index) => const SizedBox(height: 15), // here the SizedBoxed
),
);
}
I have a ScrollController in my page to work with infinite scroll but when the list builder is not in a Container the ScrollController listeners does not work.
Works
Container(
height: 400,
child: Observer(
builder: (_) {
return ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: passeiosController.passeios.length,
itemBuilder: (_, index) => PasseioCard(
passeioModel: passeiosController.passeios[index],
),
);
},
),
)
Not working
Observer(
builder: (_) {
return ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: passeiosController.passeios.length,
itemBuilder: (_, index) => PasseioCard(
passeioModel: passeiosController.passeios[index],
),
);
},
)
It worked. I had a list view builder inside a listview. Putting the controller in the parent listview worked correctly.
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.
I am trying to add 70.0px at the bottom of each of my Container item in my ListView.
I have been looking at a lot of answers from StackOverflow and trying them in many different ways, and adding padding inside ListView doesn't work somehow. However, I still couldn't tackle it.
Can someone please give me some advice please?
class PortfolioRow extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
return Container(
margin: const EdgeInsets.only(bottom: 70.0),
child: StreamBuilder(
stream: Firestore.instance
.collection('portfolio')
.where('category')
.snapshots(),
builder: (context, snapshot) {
return ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemExtent: 450.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) => portfolioContainer(
context, snapshot.data.documents[index]));
}));
...
}
Widget portfolioContainer(
BuildContext context, DocumentSnapshot documentSnapshot) {
return Align(
child: SizedBox(
height: 540,
width: 330,
child: Container( // if I add padding bottom here, there will be a pixel overflow in my container
child: Column(children: [
Container(
...
}
ListView has a named constructor for exactly that : ListView.separated(). The separatorBuilder parameter lets you specify a widget that will be added at the bottom of each item :
ListView.separated(
itemCount: 25,
separatorBuilder: (BuildContext context, int index) => Divider(),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('item $index'),
);
},
)