I have this ListView inside a container (red), and I 'm having toruble making it so that the children of the ListView start on the top of the Container instead of the middle. For example, if the ListView only had onde children, it would be in the top of the Container.
child: Container(
color: Colors.red,
width: MediaQuery.of(context).size.width,
height: 250,
child: FutureBuilder(
initialData: Map<String, dynamic>(),
future: getCurrentUserSportsPlayedList(),
builder: (context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
Map<String, UserSportAttributes> userSportAttributesMap =
Map<String, UserSportAttributes>.from(snapshot.data!.map((key,
value) =>
MapEntry(key, UserSportAttributes.fromJson(value, key))));
List<String> sportNamesList =
userSportAttributesMap.keys.toList();
List<UserSportAttributes> attributesList =
userSportAttributesMap.values.toList();
List<Padding> _tilesList = [];
for (int i = 0; i < sportNamesList.length; i++) {
_tilesList
.add(_sportsListTile(sportNamesList[i], attributesList[i]));
}
return ListView(
children: _tilesList,
scrollDirection: Axis.vertical,
physics: BouncingScrollPhysics(),
);
},
),
))
Related
I am trying to build a Nested listview but getting "RenderFlex children have non-zero flex but incoming height constraints are unbounded" error with below code.
Layers are like this...
Each item of a horizontal ListView has a Text widget and a ListView widget.
At the second level, each item of vertical ListView contains again a Text widget and a ListView.
At the third level, each item of the ListView contains a Text widget.
-Horizontal ListView
- Person's Name
- ListView
- Relation Name
- ListView
- Person's Name
Thanks in advance.
person.relations is a Map<String, List<Person>>
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Relationship Explorer"),
),
body: SafeArea(
child: BlocBuilder<RelationCubit, CubitState>(
bloc: _cubit,
builder: (_, state) {
if (state is RelationSuccessState) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (_, outerIndex) =>
_relationTreeView(context, outerIndex),
itemCount: _cubit.people.length,
);
} else {
return WaitWidget();
}
},
),
),
);
}
Widget _relationTreeView(BuildContext context, int outerIndex) {
var person = _cubit.people[outerIndex];
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(person.displayName ?? ''),
Expanded(
child: Container(
width: MediaQuery.of(context).size.width,
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: person.relations?.length,
itemBuilder: (_, index) {
var persons = person.relations?[index];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(person.relations!.keys.elementAt(index)),
Expanded(
child: Container(
width: MediaQuery.of(context).size.width,
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: persons.length,
itemBuilder: (_, index) {
var innerPerson = persons[index];
return Text(innerPerson.displayName ?? '');
},
),
),
)
],
);
},
),
),
),
],
);
}
Wrap the list view with a container and give a height.
I currently have a StreamBuilder nested inside a SingleChildScrollView that returns a Row of widgets, which is scrollable along the horizontal axis. I want to change this to a GridView with crossAxisCount: 2, that is scrollable along the vertical axis instead. Any ideas about how to do this please?
Here's my current code:
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: StreamBuilder<QuerySnapshot> (
stream: _firestore
.collection('recipes')
.where('favouritedBy', arrayContains: widget.userEmail)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final recipes = snapshot.data.documents;
List<Widget> recipeWidgets = [];
for (var recipe in recipes) {
final recipeTitle = recipe.data['recipeTitle'];
final ingredients = recipe.data['ingredients'];
final videoID = recipe.data['videoID'];
final youtubeURL = recipe.data['youtubeURL'];
final method = recipe.data['method'];
final thumbnail = recipe.data['thumbnail'];
final recipeID = recipe.data['recipeID'];
final favouritedBy = recipe.data['favouritedBy'];
final recipeWidget = FavouritesRecipeCard(
recipeTitle: recipeTitle,
videoID: videoID,
youtubeURL: youtubeURL,
recipeID: recipeID,
favouritedBy: favouritedBy,
method: method,
ingredients: ingredients,
thumbnail: thumbnail,
);
recipeWidgets.add(recipeWidget);
}
return Row(
children: recipeWidgets,
); //This is the Row I would like to change to be a GridView instead
}),
),
Problem solved! Here's the solution:
I just changed the Row to be a GridView.count widget:
return GridView.count(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
children: recipeWidgets,
);
Hope this helps someone in the future!
return Row(
GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3),
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new GridTile(
footer: new Text(snapshot.data.documentsp[index].data()[key]),
child: new Text(snapshot.data.documentsp[index].data()[key]),
),
);
},
),
);
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());
})
);
}
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'),
);
},
)
In FutureBuilder, I need to create Wrap with elements but I don't know how.
FutureBuilder(
future: _getCategories(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if(snapshot.data == null){
return Text("Wait...");
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index){
return Text(snapshot.data[index].category);
},
);
}
},
)
I need to replace ListView.builder with something like Wrap.builder or something else.
Let's say this is your List:
List<int> _items = List.generate(10, (i) => i);
You can use it in Wrap:
Using List.map
Wrap(
direction: Axis.vertical,
children: _items.map((i) => Text('Item $i')).toList(),
)
Using for-each
Wrap(
direction: Axis.vertical,
children: [
for (var i in _items)
Text('Item $i'),
],
)
To answer your question:
Wrap(
children: snapshot.data.map((item) => Text(item.category)).toList().cast<Widget>(),
)
Here's a solution,
List tags = ['one','two'];
Wrap(
children: [
for (var item in tags)
Padding(
padding: const EdgeInsets.all(8.0),
child: Chip(
label: Text(item),
),
)
],
),