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.
Related
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!
In container I am using list view builder, while I am using Axis.horizantal without declaring height of I am getting render box layout issue
you can use the combination of SingleChildScrollView and Row to replicate the Behaviour of Listview with horizontal Scroll.
An example is mentioned below, this one worked for me.
Container(
color: Colors.black,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: const [
Icon(Icons.phone),
],
),
),
),
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,
I have been working on flutter, and now have to make the Tab Bar for the page. Since I've succeeded in making the tabs, but there is one thing which is not letting me complete my task which is this,
I have a design blueprint which is like this:
Column{
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <widget>[
Text("Hello World!"),
Container(child: TabWidget())
]
}
I have not given any specific height to the container of the TabWidget() since I wanted the Tabs to take up the full height till the bottom.
TabWidget
child: TabBar(
controller: _controller,
tabs: [
new Tab(
child: Padding(
padding: EdgeInsets.only(top: 18.0),
child: Text(""),
)
),
new Tab(
child: Padding(
padding: EdgeInsets.only(top: 18.0),
child: Text(""),
)
),
]
)
),
Container(
//Deifining the height here, not deifing it will hide the content of the tabs
height: MediaQuery.of(context).size.height/2.3,
child: new TabBarView(
controller: _controller,
children: <Widget>[
new Container(
padding: EdgeInsets.only(top: 15.0),
child: Listview(
scrollDirection: Axis.Vertical,
children: <Widget> [
...
]
)
),
new Container(
padding: EdgeInsets.only(top: 15.0),
child: Listview(
scrollDirection: Axis.Vertical,
children: <Widget> [
...
]
)
)
]
)
)
]
);
Here is the catch, now I have tried my level best to get the result and hence did this :
Use of Expanded() in the TabWidget to take up the height
Use of double.infinity() in the height element of TabBarView
I have read this answer : TabBarView without bounded height, but I don't want my screen to scrollable, Silver is not required in this case. Just the TabBarView should be expanded till the bottom irrespective of from where it is starting
I don't want to give a particular height to my TabBarView, instead, I want it to take the full height till the bottom irrespective of the screen, so my height is dynamic as per the screen.
I'd like to get some inputs on this so that I'd achieve my point. I'm using ListView() in the child of TabBarView, so even if the portion size is small of the screen of the phone user will still be able to scroll the content. But the height should be till bottom, doesn't matter what the screen's size. Thanks.
Any queries are welcome here.
If you can calculate the height of other widgets in the screen above the tabBar then using MediaQuery.of(context).size.height you will get the height of the screen. Deduct the remaining height from the screen height and you can use the resulting value.
P.S. Be careful with the calculations and deduct every height value other than the tab including the safe area one that you will get from MediaQuery.of(context).padding.top & MediaQuery.of(context).padding.bottom.
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 (: