Flutter - Scrollable List of Widgets - flutter

I have a screen that displays a list of widgets, something like this:
Column(
children: listW,
),
The listW object is of type List<Widget>. The first index contains a ListTitle and all others are of type Card. The number of cards are added dynamically. Now the problem is that when the list has lets say 10 Card objects, it is hidden below the screen. I need some sort of a ScrollableView to contain my list. How can I do that since SingleChildScrollableView can bear only one widget. How can I deal with this issue?

Try changing you code to this
ListView(children: listW,)

You can use a ListView() for this.
ListView(
children: <Widget>[
//Your widgets
]
)
Keep in mind, that a list view renders all the items currently in the list, which means huge lists will cause performance issues. You can get around this using a ListView.builder, since this creates items as they are scrolled on the screen.
class FruitList extends StatelessWidget{
final List<String> fruits = [ "Apple", "Banana", "Pear", "Orange", "Kiwi" ];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(5),
child: ListView.builder(
itemBuilder: _buildFruitItem,
itemCount: fruits.length,
)
)
);
}
Widget _buildFruitItem( BuildContext context, int index ){
return Card(
child: Text( fruits[index] ),
);
}
}
You can checkout more documentation on this here: https://flutter.io/docs/cookbook/lists/long-lists

Related

How can I place different elements in a List in Flutter?

As in the image; How can I create a list structure where the list items can be selected, the user can enter data with the textField and I can use the Text() Widget?
You can use the ListView widget.
It accepts a list of widgets as it's children, so you are not limited to ListTile.
Code should look something like this:
ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
Container(), //Your widget here
Container(), //Your widget here,
Container(), //Your widget here
...
],
)

Any alternative to Expanded widgets using with ListView.builder

I need to design a screen that shows a different widget (selectedWidget) depending on which button is selected. Problem is that the content is dynamic and I have to use ListView.builder for all the APIs. And ListView.builder only works when the Row containing listview is wrapped in Expanded widget. I want to have two buttons just below my ListView, which I'm not able to achieve due to the Expanded widget which covers up the entire Column in which the ListView is present.
The code gives the basic structure which I've been using. selectedWidget is the ListView.builder widget which will be selected according to the FlatButton selected. Also the Column which contains the selectedWidget has dynamic height. It should adjust according to the size of the listview, so I cannot define a fixed height or even a maxHeight. I can only give minHeight here. And the two buttons below my ListView should be right below my ListView and take the width of the Column with flex 3.
I've also tried disabling the scroll for ListView and using SingleChildScrollView, but then my two buttons below the ListView also start scrolling, which I don't want. I need them to be static on the screen and only the ListView should scroll.
I need a solution for the above problem. I need a workaround for this Expanded widget which doesn't let me align my buttons right below my listview and gives white space. Please share if there is any alternative to ListView.builder because I don't think I can use ListView.builder without the Expanded widget. I've tried every possible structure with ListView and Expanded widget.
class MyScreen extends StatefulWidget {
#override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
#override
Widget build(BuildContext context) {
return Column(
children:[
Expanded(
child: Row(
Expanded(flex: 2,
child: Column(
children: [
FlatButton(),
FlatButton(),
FlatButton(),
FlatButton(),
]
)
),
Expanded(flex: 3,
child: Column(
children: [
Expanded(selectedWidget),
Row(children: [FlatButton(), FlatButton()], )
]
)
),
)
)
],);
}
}
Maybe you can use Flexible and set shrinkWrap: true, inside ListView. The following 2 buttons may not need Expand widget after that.
child: Column(
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) => Text(index.toString()),
itemCount: 6,
),
),
Row(
... // 2 Buttons

Queries on Flutter ListView

Im learning about listviews and I have the below two dart files, one using ListView builder and the other Listview. Both output the same result. I have been following the listview guide: https://pusher.com/tutorials/flutter-listviews
Below are my queries on listview:
I understand in the real world the data will be coming from an API and wanted to know which of the below options will be used and why?
Am i correct to understand that any widget like container, text can be child of within a listView?
In option 1 the ListView child is a function _buildListItemsFromLocation(). Is this a good practise or should we move the _buildListItemsFromLocation()code to a separate dart file?
Option1: ListView
class LocationListView extends StatefulWidget {
#override
_LocationListViewState createState() => _LocationListViewState();
}
class _LocationListViewState extends State<LocationListView> {
List<Container> _buildListItemsFromLocation() {
int index = 0;
return locationData.map((location) {
var container = Container(
child: Row(
children: [
Container(
margin: EdgeInsets.all(10.0),
child: Image(
image: AssetImage(location.imagePath),
width: 100.0,
height: 100.0,
fit: BoxFit.cover,
),
),
Container(
child: Text(location.name),
)
],
),
);
return container;
}).toList();
}
#override
Widget build(BuildContext context) {
return ListView(
children: _buildListItemsFromLocation(),
);
}
}
Option 2 - ListView.builder
class LocationList extends StatefulWidget {
#override
_LocationListState createState() => _LocationListState();
}
class _LocationListState extends State<LocationList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: locationData.length,
itemBuilder: (context, index) {
return Row(
children: [
Container(
margin: EdgeInsets.all(10.0),
child: Image(
image: AssetImage(locationData[index].imagePath),
width: 100.0,
height: 100.0,
fit: BoxFit.cover,
),
),
Container(
child: Text(locationData[index].name),
)
],
);
}
);
}
}
I use method 2 because it is easy to understand and follows the order from top to bottom so it is easy to read the code.
Any widget can be a child of another widget. Depending on how and what you use them for.
Many people say that we should create another class and then call it again rather than split as above because it affects the performance of the app. In case of using a lot but only in one screen, you can use the same method as your own.
The answer may be flawed, have nothing to give yourself.
If you don't know in advance list size, then create it through builder
1.1 If you create list and you know that elements count won't be more than ten or
twelve, you can create ListView from example1
Any widget can be in ListView. For convenience there is widget called
ListTile, which contains leading, trailing, title, subtitle widgets
its's ok

Card and ListView on single screen

I have a dropdown box and a listview below it on a screen.
On selection of a item in dropdownbox, the list view gets populated with multiple cards. As such the logic is working, but somehow having issues with the scroll configuration.
I have the main parent widget like this:
Widget build(BuildContext context) {
return Column(
children: <Widget>[locationDropdown(), showPackages(plansLoading)],
);
}
The locationDropDown() function returns a card widget with dropdown in it.
showPackages(plansLoading) returns a ListView widget whose code is like
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
return Card(
color: Colors.transparent,
child: Column(
children: <Widget>[
///...
],
),
);
)
Requirement is to keep the card in the loationDropdown() widget fixed at its place and the cards generated in showPackages's listview be scrolled.
This is the output I am getting, I am unable to scroll.
This functionality is not working. Where am I going wrong?
you can used SafeArea Widget or use Expanded widget before Listview.
ex.
Column (
children: <Widget>[
new TextField(
decoration: new InputDecoration(
labelText: "Search something"
),
Expanded(
ListView(),
),
]
)

Adding both vertical and horizontal scrolling to ListView

How can I make the Rows inside a vertical ListView, scrollable horizontally.
This is what my app looks like:
I want the user to be able to scroll the ListView both horizontally (to see the contents of the Row) and vertically to see new list items. This behavior is like how you would scroll a DataTable in Flutter:
Here is the build method (based on the Flutter project template):
#override
Widget build(BuildContext context) {
final List<String> rows = [
"This is a row with some very long text ... That goes on and on",
"This class is the configuration for the state.",
"case the title) provided by the parent (in this case the App widget) and",
"always marked \"final\"."
];
return Scaffold(
appBar: AppBar(title: Text("ListView")),
body: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
for (final String row in rows)
Row(
children: <Widget>[Text(row)],
)
],
),
);
}
Update: Wrapping the Text in Expanded doesn't work as it causes the text to wrap onto multiple lines. I want the text to remain on a single line.
Finally
After a deep search found this finally
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: new SizedBox(
width: 1000.0,
child: new ListView.builder(
itemBuilder: (BuildContext context, int i) {
return new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: new List.generate(5, (int j) {
return new Text("$i,$j");
}),
);
},
),
),
),
);
}
Original source Vote up his answer too