How can I add a button above a list? - flutter

I tried to add a RaisedButton above the ListView. I used a Colum but I got an error. Can anybody tell me where my mistake is? Thanks in advance!
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Test"),
onPressed: null,
),
ListView.builder(
itemCount: exercises.length,
itemBuilder: (context, i) {
return Container(
child: Text(
exercises[i]["text"],
),
);
},
),
],
),

Adding to #Viren answer, You should use Flexible instead of Expanded
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Test"),
onPressed: null,
),
Flexible(
child: Container(
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, i) {
return Container(
child: Text(
'jitesh',
),
);
},
),
),
)
],
),
Please find diff Flutter: Expanded vs Flexible

You need to wrap your listview with Expanded widget.
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Test"),
onPressed: null,
),
Expanded( // added widget
child: ListView.builder(
itemCount: exercises.length,
itemBuilder: (context, i) {
return Container(
child: Text(
exercises[i]["text"],
),
);
},
),
],
),
)

Related

How to use listview with other widgets?

I want to use ListView with other widgets , but I can't. When I use container for Listview, I can't view any other widgets. How can I do it?
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
ListView.builder(),
RaisedButton(
child: Text('Text'),
onPressed:(){})
])));
You shouldn't nest scroll views at all if you are trying to show some widgets based on a list, dart lets you use for inside any collection also you can use List.generate, or list.map with the spread operator
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
for(final item in list) widget,
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
or
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
...list.map((item)=> widget).toList(),
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
or
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
...List.generate(list.length, (index)=> widget).toList(),
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
This is because you are using ListView inside Column, both ListView and Column take the full screen available to them, as this way we can only see ListView on the screen, to resolve this we have to shrink ListView to its exact size, for it shrinkwrap: true is used.
ListView.Builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
)
physics: NeverScrollableScrollPhysics(), is used here to stop ListView scrolling, you have added SingleChildScrollView() which scroll entire page
Add ShrinkWrap to The ListView
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children:[
Container(),
Container(),
]
),
RaisedButton(
child: Text('Text'),
onPressed:(){})
])));
for More Advanced Scrolling Challenges like More than One ListView in Column I Suggest you add a ScrollPhysics
u need use Expanded here and set data to ListView.builder
final items = List<String>.generate(10000, (i) => 'Item $i');
Column(children: [
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
),
AnyWidget(...)
])
You have to wrap your ListView widget with Expanded or if you want to wrap it with Container then you must have to give Container height or width
Try this Code...
Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: 4,
shrinkWrap: true,
itemBuilder: (context, index) {
return Text('Hello');
}
),
RaisedButton(
child: Text('Text'),
onPressed: () {}
)
]
)
)
);
In this example, the ListView and the other widget (a Container with yellow color) are both children of the Column widget. By doing this, you can ensure that the ListView and the other widgets can both be displayed on the screen.
Column(
children: <Widget>[
Container(
height: 200,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160.0,
color: Colors.red,
),
Container(
width: 160.0,
color: Colors.blue,
),
Container(
width: 160.0,
color: Colors.green,
),
],
),
),
Container(
height: 200,
color: Colors.yellow,
),
],
)

Scrollable HomeScreen in Flutter

I wonder why that doesn't work. Maybe one can help me, I think it's just a small mistake.
I would like to be able to scroll the whole screen. The container with the "CompanyCard" widget can be scrolled vertically.
return Column(
children: <Widget>[
SearchBox(),
Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) => CompanyCard(),
),
),
],
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
);
horizontal: Facebook, Google Twitter (already works)
vertical: the whole screen (not working)
Wrap SingleChildScrollView to the widgets you like to scroll
return Column(
children: <Widget>[
SearchBox(),
SingleChildScrollView(
child: Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) => CompanyCard(),
),
),
],
),
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
);
New edit:
To make the whole page scrollable, wrap the page in SingleChildScrollView:
Full Code:
return Container(
child: SingleChildScrollView(
child: Expanded(
child: Column(
children: <Widget>[
SearchBox(),
SingleChildScrollView(
child: Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) =>
CompanyCard(),
),
),
],
),
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
),
),
),
);
You need to specify an explicit height to your List View. By default a List View has infinite height / width.
To be able to scroll the entire screen, you need to wrap your root widget inside a SingleChildScrollView and then specify a height for the List View container. Somewhat like this :-
body : SingleChildScrollView(child :...
... Other widgets...
Container (
height :200,
width :MediaQuery.of(context).size.width, // so that ListView occupies the entire width
child : ListView.builder(...
I think ListView in Column needs height.
I wrapped ListView with Container and give a some height.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("Home page"),
elevation: 5.0,
),
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
SizedBox(child: Text('asdf')),
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) =>
SizedBox(width: 200, child: Text('aaa')),
),
),
SizedBox(child: Text('asdf')),
SizedBox(child: Text('asdf')),
SizedBox(child: Text('asdf')),
],
),
),
),
);
}

Flutter - Container width and height fit parent

I have a Card widget which includes Column with several other Widgets. One of them is Container.
Widget _renderWidget() {
return Column(
children: <Widget>[
Visibility(
visible: _isVisible,
child: Container(
width: 300,
height: 200,
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: ListView.builder(
itemCount: titles.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(icons[index]),
title: Text(titles[index]),
),
);
},
)),
),
],
);
}
Here, if I don't specify width and height I get error. But, is there a way to make them to fit parent element?
EDIT
Full code:
return ListView(
children: <Widget>[
Center(
child: Container(
child: Card(
margin: new EdgeInsets.all(20.0),
child: new Container(
margin: EdgeInsets.all(20.0),
width: double.infinity,
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: Column(
children: <Widget>[
FormBuilderDropdown(
onChanged: (t) {
setState(() {
text = t.vrsta;
});
},
validators: [FormBuilderValidators.required()],
items: user.map((v) {
return DropdownMenuItem(
value: v,
child: ListTile(
leading: Image.asset(
'assets/img/car.png',
width: 50,
height: 50,
),
title: Text("${v.vrsta}"),
));
}).toList(),
),
],
),
),
Container(child: _renderWidget()),
text.isEmpty
? Container()
: RaisedButton(
child: Text("Submit"),
onPressed: () {
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value.toString());
print(formData.startLocation);
getAutocomplete();
}
},
)
],
),
)),
),
),
],
);
}
Just set the height and width property of your Container to double.infinity
Solution Code:
Widget _renderWidget() {
return Column(
children: <Widget>[
Visibility(
visible: _isVisible,
child: Container(
width: double.infinity,
height: double.infinity,
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: ListView.builder(
itemCount: titles.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(icons[index]),
title: Text(titles[index]),
),
);
},
)),
),
],
);
}
You are using ListView inside Column which is why you need to specify height in your Container to prevent errors.
The best way is to use Expanded or Flexible as parent of your ListView
Expanded(
child: ListView.builder(...)
)
Update:
Widget _renderWidget() {
return Column(
children: <Widget>[
Visibility(
visible: _isVisible,
child: Expanded(
child: ListView.builder(
itemCount: titles.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(icons[index]),
title: Text(titles[index]),
),
);
},
),
),
),
],
);
}

Flutter dynamic height of ListView

I am developing a Flutter application and I want to dynamically adjust the height of the ListView.
I want the list to have a maximum height of 200. If the height is more than that, user will have to scroll to reach the bottom. If height is below 200, it will take only as much space as needed.
Preview of application: Screenshot. As you can see Restaurants nearby is pushed to the very bottom of the page. I want the ListView to only take height of 200 or less so that the content below isn't pushed to the bottom.
Here is my current code:
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
],
),
Flexible(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
You are using Flexible widget, that's why your ListView expands. You have to change Flexible to ConstrainedBox and add shrinkWrap: true to your ListView.
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200, minHeight: 56.0),
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
More info here: https://api.flutter.dev/flutter/widgets/ConstrainedBox-class.html
You can use LimitedBox
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(...),
Divider(),
Row(...),
LimitedBox(
maxHeight: 200.0,
child: ListView.builder(...),
),
Text(...),
],
),
Recommended solution in case when the incoming constraints are unbounded
Consider wrapping the ListView into this
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Note that:
shrinkWrap of ListView is set to true
mainAxisSize of Column is set to MainAxisSize.min
maxHeight of LimitedBox is set to 200
A complete snippet:
import 'package:flutter/material.dart';
class DebugWidget extends StatefulWidget {
#override
_DebugWidgetState createState() => _DebugWidgetState();
}
class _DebugWidgetState extends State<DebugWidget> {
int _itemsCount = 1;
#override
Widget build(BuildContext context) {
Widget child = Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
RaisedButton(
child: Text('+1'),
onPressed: () {
setState(() {
_itemsCount += 1;
});
},
),
RaisedButton(
child: Text('-1'),
onPressed: () {
setState(() {
_itemsCount -= 1;
});
},
),
],
),
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
return Scaffold(
body: child,
);
}
}
I found a solution to this problem. you should wrap your ListView with LimittedBox or ConstraintBox and give them maxHeight and set shrinkWrap property of ListView to true. the solution would be something like this.
LimitedBox(
maxHeight: 200,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
I see that this question has never been answered only with giving a fixed height, so here is what works for me.
For some reason if you set the shrinkwrap to true it doesn't look like it is working but it does, the problem is in the padding settings of the ListView, set the padding to edgeinstets.zero. That fixes it for me.
Wrap inside a Flexible
ShrinkWrap true
Padding, zero
and if needed the column to MainAxisSize.min.
Hope it helps some people.
Example of my code:
Flexible(
child: Container(
decoration: BStyles.cardDecoration1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'PRODUCTION TASKS',
),
const SizedBox(
height: textVerticalSpacing,
),
Flexible(
child: ListView.builder(
itemCount: recentTasks.length,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return TaskCard(
task: recentTasks[index],
widthInfo: MediaQuery.of(context).size.width * 0.6,
);
},
),
),
const SizedBox(
height: itemSpacing,
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () { },
child: const Text(
'View more',
),
),
),
const SizedBox(
height: textVerticalSpacing,
),
],
),
),
),
),
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200.0),
child: [your child here],
)
This make your child's height not bigger than 200.0
You can always size the ListView container as % of the viewport (assuming of course that the other widgets also are sized in the same manner):
return Container(
height: MediaQuery.of(context).size.height * 0.75,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Card(...

Can't set ListView into LayoutBuilder Widget (Flutter)

I need to have some structure like this
I use LayoutBuilder to get the height of content (between App Bar and TabsBottomNavigation). Here i build Profile Info Container and want to build ListView with some List Tiles, but when I try to build it in Layout Builder I have errors in console.
If I create ListView out of LayoutBuilder it works!
Please help me to solve it.
My code below:
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
height: viewportConstraints.maxHeight * .44,
color: Theme.of(context).primaryColor,
padding: EdgeInsets.only(bottom: 2),
child: Align(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildProfileImage(context),
SizedBox(height: 17),
Text(userName)
],
),
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
)
],
),
)
],
),
),
);
},
);
}
Use below build method will work in your case. (I have checked and it's working, so I hope it will work in your case also and will fit in your requirement.)
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Container(
child: Column(
children: <Widget>[
Container(
height: viewportConstraints.maxHeight * .44,
color: Theme.of(context).primaryColor,
padding: EdgeInsets.only(bottom: 2),
child: Align(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildProfileImage(context),
SizedBox(height: 17),
Text(userName),
],
),
),
),
SizedBox(height: 16),
Flexible(
child: ListView(
children: <Widget>[
Card(
child: ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
),
),
],
),
),
],
),
);
},
);
}
I think SingleChildScrollView is of no use in this case so I removed it but you can use it if you fill so.
You still need to do some UI improvement as per your wish as this is the basic structure as per your requirement.
Hope this will help you.
You are using the LayoutBuilder in a wrong way.
It's supposed to be used to change the layout with the size of the device and/or orientation.
What you are trying to do is best accomplished with MediaQuery:
MediaQuery.of(context).padding.top //APP bar height
MediaQuery.of(context).padding.bottom //Bottom bar height
MediaQuery.of(context).size.height //Screen height
Widget build(BuildContext context) {
return Column(
children:<Widget>[
Expanded(
child:LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
height: viewportConstraints.maxHeight * .44,
color: Theme.of(context).primaryColor,
padding: EdgeInsets.only(bottom: 2),
child: Align(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildProfileImage(context),
SizedBox(height: 17),
Text(userName)
],
),
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
)
],
),
)
],
),
),
);
},
),
),
]
);
}
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ListView(
shrinkWrap: true,
children: <Widget>[
new Container(
height: MediaQuery.of(context).size.height/3,
color: Theme.of(context).primaryColor,
padding: EdgeInsets.only(bottom: 2),
child: Align(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildProfileImage(context),
SizedBox(height: 17),
Text(userName)
],
),
),
),
new ListView(
shrinkWrap: true,
children: <Widget>[
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
)
],
)
],
),
);
},
);
}
If you read the error log, it says non-zero flex incoming but constraints are unbounded. To understand that clearly, imagine Flutter is trying to draw pixels of something that not finite. That's the our problem.
Widgets like ListView or SingleChildScrollView are flex widgets and has no limits unlike Column or Row.
If you have children that sizes are not definite, then you have to define flex for your ListView. For that, you can use shrinkWrap or Flexible, Expanded widgets for both ListView itself or children.
And here is the my solution, simplified as much as possible:
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return ListView(
shrinkWrap: true, // That's it
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
height: viewportConstraints.maxHeight * .44,
padding: EdgeInsets.only(bottom: 2),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildProfileImage(context),
SizedBox(height: 17),
Text(userName)
],
),
),
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
),
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
),
ListTile(
leading: Icon(Icons.print),
title: Text('asdad'),
)
],
);
},
);
}
Meanwhile, you have too many children that does nothing. If you want different scrolling behavior inside the Profile Info and ListTiles parts, tell me because we will must create yet another ListView for achieve that.
Also if you share your buildProfileImage widget, we can optimize your code even further, because you may even not need the LayoutBuilder widget in this case.