When creating a very simple scrollable list in Flutter, what are the advantages and disadvantages of saying (where widgets is List<Widget> == true):
Option 1:
var widget = new SingleChildScrollView(
child: new Column(
chidren: widgets
));
Option 2:
var widget = new ListView(children: widgets);
ListView:
Listview Widget shows the unlimited number of children inside it, but the main advantage of using ListView is it renders only visible items on the screen perhaps more specifically I would say ListView.Builder()
Column
The column is used when we have to draw different widgets in the list. If items increase in the column then SingleChildScrollView is used for scrolling purposes.
For More Reference:
https://medium.com/flutterworld/flutter-problem-listview-vs-column-singlechildscrollview-43fdde0fa355
Definitely go for option 2.
ListView have a few cool optimisations. https://youtu.be/UUfXWzp0-DU?t=33m38s
Related
I need to get the whole list.builder height including the part that is out of the screen view
The List children vary in height
i used the GlobalKey method but it is giving me only the height of the list shown in the screen
I found this solution and it's working and give me the full list.builder height after scrolling event
but when adding more children to the list.builder by changing the state
this code doesn't work anymore
scrollController.addListener(() {
double? fullListViewHeight;
double fullListHeightHelper = listKey.currentContext!.size!.height +
scrollController.position.extentAfter;
fullListView ??= fullListHeightHelper;
}
listview.builder only build the item that shown to user, in order to get the height with GlobalKey method, you can use listView which build all item at the same time. If you don't know how pass your list to listView , see this example:
List yourList = [...];
_buildList(){
List<Widget> _children =yourList.map((e) => YourListItem()).toList();
return ListView(
key:yourKey,
children: _children,
);
}
it is giving me only the height of the list shown in the screen
yes.. thats correct. because listview not render all the children. see the documentation of listview:
The ListView.builder ...constructor is appropriate for list views with
a large (or infinite) number of children because the builder is called
only for those children that are actually visible.
to get exact height of all children is impossible. since when the widget child is scrolled out of view, the associated element subtree, states and render objects are destroyed.
I think you need to calculate it manually or make the children height is same for all.
To calculate it, you need to make each item the same height. Then,
To get the height of the ListView.builder you simply multiply the height of each item by the length of the ListView.builder.
I have 2 rows in my screen, the first row is consist of dropdown button and elevation button and the second row is where the stream builder located, I used flexible so that the stream builder is scrollable. What I want is every time I scroll the stream builder I want the first row to follow the scroll not stay in the screen.
This is how my widget set:
Scaffold
-Column
-Row
-Dropdown button
-Elevated buton
-Flexible
-Streambuilder
-stack
-listview
Just like in facebook everytime you scroll down the "what's in your mind" controller disappers too, not floating like an app bar
Inside Listview add physics: NeverScrollableScrollPhysics()
//
Listview(
physics: NeverScrollableScrollPhysics(),
return .....;
)
//
Follow this pattern.
If you want that widget to disappear when you scroll, you need to wrap your Column in a SingleChildScrollView which you will need to wrap in a Flxible
Code:
Flexible(
child: SingleChildScrollView(
child: Column(
//your normal code insode Column
Depending on your code, you may also need to make the ListView not scroll (as suggested by Rafid):
Listview( physics: NeverScrollableScrollPhysics()
Since i want this to be my layout i was trying to implement it with a showModalBottomSheet but the problem is that this widget only works on the button click as it is showing me error when i am trying to call the method as it is in the initState method. So then I started to work with bottomSheet value present in the scaffold but then the background is being displayed only upto the starting of the bottom sheet creating the distance between the model sheet and the background whereas I want it to overlap like in the image..How should I prepare this layout.
There is no such parameter as "bottomSheet" in Scaffold, there is one called bottomAppBar, which is used for making Bottom Bars like the one on the Youtube Android App. So this should help you make the basic structure.
Use a Stack widget to put widgets on top of each other, in first layer, add the image using the NetworkImage widget, then in the second layer, make a Column, like this:
#override
Widget build() => Scaffold(
body: _body(),
);
_body() => Stack(
children: <Widget>[
NetworkImage(your_url_here),
Column(
children: <Widget>[
_basicDetails(),
_guidePanel(),
]
),
]);
Then create 2 new methods after the _body method like this:
_body() => Stack(...);
_basicDetailsPage() => Container();
_guidePanel() => Container();
Create your layout in these 2 methods. Comment if you need more help :)
For additional help, please join the Facebook Group "Let's Flutter With Dart"
What is the difference between Listview.builder and Listview?
Can we use ListView.builder to submit forms?
I am using the Listview.builder now to create forms.
From official docs:
https://api.flutter.dev/flutter/widgets/ListView/ListView.html
ListView: Creates a scrollable, linear array of widgets from an
explicit List.
This constructor is appropriate for list views with a small number of
children because constructing the List requires doing work for every
child that could possibly be displayed in the list view instead of
just those children that are actually visible.
https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html
ListView.builder Creates a scrollable, linear array of widgets that
are created on demand. This constructor is appropriate for list views
with a large (or infinite) number of children because the builder is
called only for those children that are actually visible.
Basically, builder constructor create a lazy list. When user is scrolling down the list, Flutter builds widgets "on demand".
Default ListView constructor build the whole list at once.
In your case, default construct works fine, because you already now how many widgets should put on Column().
The main difference between ListView and ListView.builder
The ListView constructor requires us to create all items at once. This is good when list items are less and all will be seen on the screen, but if not then for long list items its not the good practice.
whereas
the ListView.Builder constructor will create items as they are scrolled onto the screen like on-demand. This is the best practice for development for List widget where items will only render only when items are going seen on the screen.
ListView.builder() builds widgets as required(when they can be seen). This process is also called "lazily rendering widgets".
To see the difference between each one go visit ListView Class.
And sure, you can create Forms with ListView.builder(), but I've found some problems trying it.
I can't put it into any ListView(), either Column(), to put them if there's any more items than just the Form().
I couldn't even add a Button at the of the ListView.builder() even using a conditional to put it when the last index is reached. Because of that, you have to use textInputAction: TextInputAction.done to perform some kind of action at onFieldSubmitted:
The best way to get the Fields data I've found was to add them all into an array when the onSaved:method is called, and I don't think that's a good way to go (maybe it is).
With that being said, that's what I used to make it work:
body: Form(
key: _key,
child: Container(
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return TextFormField(
textInputAction: TextInputAction.done,
validator: (text) {
if (text.isEmpty) {
return "The text is empty";
}
},
onFieldSubmitted: (text) {
_onSaved();
},
onSaved: (text) {
form.add(text);
},
);
},
),
),
),
void _onSaved() {
if (_key.currentState.validate()) {
_key.currentState.save();
print(form);
}
}
And the result:
I/flutter ( 7106): [fjjxjx, hxjxjcj, jxjxjfj, jfjfj, jxjxj]
This answer for those who are coming from native android background.
ListView is like listview in android
ListView.builder is recyclerView in android
In case you don't know recyclerView only render those view which are visible in screen and reuse them again and again to save resources.
RecyclerView when there is alot of data.
Let's say, I have a chat screen that looks like this.
Now, when the user clicks the "Press when ready" button, the method fetchNewQuestion() is called.
My intention is that this will make a HTTP request, and display the result using
_buildUsersReply(httpResponse);
But, the problem is that this return must be made inside the current scaffold's widget as a child under the existing children, so that it is built at the bottom with the previous ones still there. The result would be like this:
You can find my complete code here.
Is this possible to be done pro-grammatically? Or do I have to change the concept of how I do this?
[Update, I now understand that my approach above is wrong and I have to use a listview builder. CurrentStatus below shows my progress towards achieving that goal.]
Current status:
I have built a list of Widgets:
List<Widget> chatScreenWidgets = [];
And on setState, I am updating that with a new Widget using this:
setState(() { chatScreenWidgets.add(_buildUsersReply("I think there were 35 humans and one horse.")); });
Now at this point, I am not sure how to pass the widget inside the scaffold. I have written some code that does not work. For instance, I tried this:
Code in the image below and in the gist here:
Just for future reference, here is what I really needed to do:
1. Create a list of widgets
List<Widget> chatScreenWidgets = [];
2. Inside my method, I needed to use a setState in order to add elements to that list. Every widget I add to this will be displayed on ths Scaffold.
`setState(() {
chatScreenWidgets.add(_buildUsersReply("Some Text"));
});`
3. And then, load that inside my Scaffold, I used an itemBuilder in order to return a list of widgets to my ListView. I already had that ListView (where I was manually adding children). Now this just returns them through the setState method inside my business logic method (in this case, fetchNewQuestion()).
body: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 0),
child: new ListView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 25),
itemCount: chatScreenWidgets.length,
itemBuilder: (BuildContext context, int itemCount) {
return chatScreenWidgets[itemCount];
}
),
),
],
),
);`
I hope this helps future flutter engineers!
forget about the scaffold the idea is about what you really want to change, lets say it is
a list and your getting the data from an array if you update the array, then the list will update,if it is another type widgets then you can handle it in a different way i will edit this answer if you clarify what each part does in your widget as i cant read your full code.
first you have to create an object with two attributes one is the type of the row(if it is a user replay or other messages) and the second attribute is the string or the text.
now create a global list in the listview class from the above object, so you get the data from the user or even as a news and you create a new object from the above class and add your data to it and add it to the list.
item builder returns a widget so according to the the widget that you return the row will be set , so according to the data in the object call one of your functions that return the views like _buildUsersReply(string text).
if you have any other question you can ask :) if this what you need please mark it as the answer.