Flutter, Nesting scrollable (or list) views - flutter

Can anyone clarify for me what I have shown in the 'image' attached is achievable in flutter? if yes, how? explaining the image is a bit hard.
I am new to flutter and trying to nest some scrollable views inside each other.
at first I tried to achieve this by nesting simple scrollable row and columns inside each other but faced some errors and exceptions (unbound height and width).
I searched and found out it is better to use 'CustomScrollView' for nesting lists in each other. tried it but haven't achieved what I want yet.
Any help/hint on how to achieve this would be much appreciated.
Nested Scroll Views

This is definitely possible, and you could use an approach like below, which is inspired by another question on stack overflow. I recommend reading that for better clarification -- here.
Edit: Wrapping the Row widget in a SingleChildScrollView would make the entire page scrollable.
body: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: X,
itemBuilder: (BuildContext context, int index) => ...
),
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: Y,
itemBuilder: (BuildContext context, int index) => ...
),
),
],
);
If this doesn't help, I'd suggest finding flutter repositories of e.g. Netflix clones or other existing apps known to have scroll views inside a list view.

#bragi, thanks for the answer,
I followed what you suggested and after some trial and error, I finally got it working.
But in terms of efficiency and how the application will respond/render I am not sure if this was the best way to do it:
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
// mainAxisSize: MainAxisSize.min,
children: [
makeColumn(),
makeColumn(),
makeColumn(),
makeColumn(),
makeColumn(),
],
),
),
Widget makeColumn() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
width: 150,
height: 150,
color: Colors.green,
),
SizedBox(
width: 150,
height: 500,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(), ....
For some reason, the Expanded widget did not work so I had to wrap my second column with SizedBox!

Related

dynamically switch scroll physics form never scroll to scroll

The title might not be totally accurate but forgive me I don't really know what to write. I am trying to create an effect where a noScroll phyicas Listview that is nested with other elements in a SingleChildScrollView, would need to change to a scrollable physics when it reaches the top of the SingleChildScrollView (thus occupying the whole view) in order to utilize the lazy loading of items.
I must say I ma trying to avoid rebuilding the nested Listview because of that cost and especially the cost of building it with the NeverScrolling physics since that would stall the main UI thread until all items are built.
The necessity of using the NeverScrolling physics in the first place it to allow the SingleChildScrollView to properly scroll (if the list view is set to normal scrolling, the SingleChildScrollView will not be able to scroll if the gesture is coming from the nested Listview)
My code looks like this :
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Material(
child: Container(
child: Column(
children: <Widget>[
ItemListDevider(),
Container(
height: 120,
child: Container(height:120)
),
ItemListDevider(),
Flexible(
fit: FlexFit.loose,
child: THeWidgetHoldingTheListView(album),
)
],
),
),
),
)
// the build method of the THeWidgetHoldingTheListView widget would return this :
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Flexible(
child: ListView.builder(
controller: controller,
shrinkWrap: true,
itemExtent: FixedItemExtent,
physics: AlwaysScrollableScrollPhysics(),
itemCount: FixedItemCount,
itemBuilder: (context, index) {
return MyCard()
},
),
),
],
),
),
MyScrollbar(
controller: controller,
),
],
),
)
*Note: * I had the idea of creating a custom ScrollPhysics that starts as a NeverScrollPhysics and the switches on a certain scroll offset but that wouldn't change the fact that I have to load the entire list as a Neverscroll and thus stalling the main UI thread.
Is there a way to get around this change of scroll physics, if not how can I implement it without compromising on performance like mentioned above.

How to fix text overflow problem and make a card larger in Flutter?

I'm building out an app in flutter and I want to display a few cards in a list-view. The problems I'm facing are the following:
I get a text-overflow when I have Text widgets in a column.I semi-fixed this by wrapping the Text widget in an Expanded widget, but it looks a bit cutoff (ex. "Question: How do you do problem 2?" (refer to picture below)).
I want to build a larger card with a greater height and more room/white space. I've tried wrapping my column widget in a container and set the height manually, but that doesn't seem to do anything.
Here is what the card looks like right now:
Relevant code shown below:
itemBuilder: (context, index) => snapshot
.data.metadata.isFromCache
? _buildListItem(context,
snapshot.data.documents[index])
Widget _buildListItem(BuildContext context, DocumentSnapshot document) {
return document.data['didProblems']
? Card(
child: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('${document.data['fullName'].toString()}'),
SizedBox(
height: 5.0,
),
Text('HW Assignment: ${document.data['title'].toString()}'),
SizedBox(
height: 5.0,
),
Text('Problems attempted: ${document.data['problems']}'),
Expanded(child: Text('Question: ${document.data['question'].toString()}'), flex: 1,),
],
),
),
),
)
Any help is appreciated. Thanks in advance!
if u r using listview then set itemExtent property to ur convenience e.g.
ListView.builder(
itemCount: 10,
itemBuilder: (_, int index) => YourWidget(),
itemExtent: 150,
),
Even after wrapping your text in an Expanded you have to set overflow to TextOverflow.clip
Try this
Expanded(child: Text('Question: ${document.data['question'].toString()}', overflow: TextOverflow.clip), flex:1,),

Flutter: Container + ListView scrollable

I have a page with container + listView. Now the listView is scrollable, but I would like the whole page to be scrollable. (so if the user scrolls, the container goes 'away')
Column(
children: <Widget>[
Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text("")),
ListView(
children: posts,
),
],
),
Is this possible, and how can it be achieved?
Thanks!
You can wrap the whole page with a SingleChildScrollView
here is an example:
SingleChildScrollView( // <- added
child: Column(
children: <Widget>[
Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text("")),
ListView(
shrinkWrap: true, // <- added
primary: false, // <- added
children: posts,
),
],
),
);
for more info about see this question
What if you don't use Column and use ListView.builder and
according to indexes you show the widget.
For example on 0 index you show the Container.
This way you don't have to use any different widget for scrolling
and as per your requirement the container will scroll with the list.
This way there is no chance that you will get any overflow error
like you were getting while using Column.
Plus point of ListView.builder is that your posts will be created lazily and that is efficient way of creating ListView in Flutter. No matter how many posts you have your UI will not lag.
This at first may look like a hack but according to your requirement that the container must also be able to get scrolled, this solution makes sense to me because Container can be considered as a first element of the list.
Let me know if it works for you or not.
Following is the working code for your reference:
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: posts.length + 1, // +1 because you are showing one extra widget.
itemBuilder: (BuildContext context, int index) {
if (index == 0) {
return Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text(""));
}
int numberOfExtraWidget = 1; // here we have 1 ExtraWidget i.e Container.
index = index - numberOfExtraWidget; // index of actual post.
return posts[index];
},
);
}
I hope this works for you, in case of any doubt please comment.
There are multiple ways you can achieve what you want. The only problem is that if you have large number of posts, listview with children posts, as shrinkWrap is set to true, will take time to calculate its required height, for that it will have to populate all of its children.
First
ListView(
children: <Widget>[
Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text("")),
ListView(
physics: NeverScrollableScrollPhysics(),
primary: false,
shrinkWrap: true,
children: posts,
),
),
],
),
Second
SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text("")),
ListView(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
children: posts,
),
],
),
),
use SingleChildScrollView then Container with hard coded container height, then list view builder, that should fix your issue.
I tried the following:
SingleChildScrollView(
child: Container(
height: 1000,
width: 400,
child: ListView(
children: <Widget>[
Container(
color: Colors.white.withOpacity(0.95),
width: 400,
height: 400,
child: Text("")),
ListView(
children: posts,
),
],
),
),
),
This works, but I would like that the container has a dynamic height and width? Is that possible? Thanks!

Flutter Fexible Widget doesn't resize when keyboard shows

So I am working on app which has a chat screen, So I finished with most of the functionality but I noticed that listView isn't resizing when the keyboard shows but the message input does move up.
As you can see Input does move up but not the ListView so I tried to move the ListViewto bottom when the keyboard shows up by moving it to bottom using ScrollController but it also didn't work
Here's my current implementation:
chat_view.dart
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
MessageListView(),
ChatInputToolbar(),
]
)
);
message_list_view.dart
Flexible(
child: ListView.builder(
controller: scrollController,
shrinkWrap: true,
reverse: false,
itemCount: messages.length,
itemBuilder: (context, i) {}
)
);
I think that you should wrap your container into SingleChildScrollView, maybe that will help you. I would write something like this:
return SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
MessageListView(),
ChatInputToolbar(),
]
),)
);
Use Scaffold widget at the start of your widget tree, it solved my problem
In your Scaffold, set resizeToAvoidBottomPadding property to false then try:
resizeToAvoidBottomInset : false,

Flutter Gridview in Column. What's solution..?

I have a problem with gridview and column. In this case, i want put an image in upper of gridview. Please give me a solution..
return new Container(
child: new Column(
children: <Widget>[
new Container(
child: new Image.asset(
"assets/promo.png",
fit: BoxFit.cover,
),
),
new Container(
child: new GridView.count(
crossAxisCount: 2,
childAspectRatio: (itemWidth / itemHeight),
controller: new ScrollController(keepScrollOffset: false),
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: new List<Widget>.generate(16, (index) {
return new GridTile(
header: new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.centerRight,
child: new Icon(
Icons.shopping_cart,
size: 20.0,
color: Colors.red,
),
),
child: new MyList(
nomor: '$index',
));
}),
),
),
],
),
);
and this is the result:
Flutter Gridview in Column
You just need to put your grid view into Expanded widget, for example:
body: new Column(
children: <Widget>[
new Expanded(
child: GridView.count(
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this would produce 2 rows.
crossAxisCount: 2,
// Generate 100 Widgets that display their index in the List
children: List.generate(10, (index) {
return _buildCard(index);
}),
),
),
new Text("text")
],
),
Reason for the error:
Column expands to the maximum size in main axis direction (vertical axis), and so does the GridView (scroll direction is vertical by default)
Solution
You need to constrain the height of the GridView, so that it expands to fill the remaining space inside Column, there are several ways of solving this issue, use whichever suits you better.
If you want to allow GridView to take up all remaining space inside Column use Flexible.
Column(
children: <Widget>[
Flexible(
child: GridView(...),
)
],
)
If you want to limit your GridView to certain height, you can use SizedBox.
Column(
children: <Widget>[
SizedBox(
height: 200, // constrain height
child: GridView(...),
)
],
)
If your GridView is small, you may try shrinkWrap property on it.
Column(
children: <Widget>[
GridView(
shrinkWrap: true, // use it
)
],
)
If Column is the parent of GridView then it will give rendering issue as
It happens because Column and GridView both take the entire space of the screen individually which is there default behavior(Default axis of scrolling is Vertical).
Solution:
To solve the above problem we have to disable scrolling of GridView, This can be possible by shrinkWrap and physics property
shrinkWrap:true - With this GridView only occupies the space it needs
physics: NeverScrollableScrollPhysics() - It disables scrolling functionality of GridView, which means now we have only SingleChildScrollView who provide the scrolling functionality.
Code:
SingleChildScrollView
Column
GridView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
//...
)
The answer mentioned by #RuslanLeshchenko is correct but if it is still not working for you, trying the following properties on GridView
Try changing shrinkwrap to true
Apply physics: BouncingScrollPhysics()
Inside your Gridview make sure to add this 2 properties.
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
Just wrap with scaffold and scrollview
Scaffold(
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
child: Column(
children: [
...
Tested working on dialog model aswell.
I had the same problem and couldn't fix.
Then again I used a GridView.builder().
I changed it to GridView.count and added shrinkWrap: true and physics: NeverScrollableScrollPhysics() as mentioned in the other comments.
It works fine now. Thanks!
You can solve it by these two properties and change them as follows :
shrinkWrap: true,
primary: false,
shrinkWrap will wrap your and will handle overflow.
Through primary we can set either you want to make this list scrollable or it's parent list. By setting it to false it allows to take scroll of parent list or scrollable view.
NOTE : You can also wrap your column with SingleChildScrollView to have scroll in your view.
Happy Fluttering !
Try changing childAspectRatio property of GridView to 0.8 or lower.
body:Container(
body: Container(
child: Column(
children: [
Text('Exemple'),
Expanded(
child: GridView.count(
children: <Widget>[
//Widgets
]
)
)
]
)
)
Just wrap GridView inside ListView
Column(
children: <Widget>[
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
GridView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
),
],
),
)
Also it works with SingleChildScrollView
SingleChildScrollView(
child: Column(
children: <Widget>[
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
GridView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
),
],
),
)
)
Works like a charm (: