I'm working on a custom calendar package but I'm having some performance difficulties while doing that.
My calendar layout is built from PageViews and each pageview contains a Gridview and each GridView contains 42 children representing the days of the month. Like this:-
Issue -
The problem is with scrolling the pageview. When I scroll to the new PageView the new PageView gets build and it builds its GridView and GridView builds its Children. All these tasks while scrolling leads to jank in scrolling animation.
Note: Scrolling to previous PageViews is smooth because I'm using AutomaticKeepAlives in PageView which stops PageView from rebuilding constantly on scroll.
DartPad -
The example DartPad for the above calendar can be found here - https://dartpad.dev/?id=762d835c5b9acadd785ee9269294c1e6
Now, what I'm looking for are the ways through which I can improve its performance.
Maybe I can somehow reuse the components for GridView children's dates by manually caching them by storing them as fields somewhere. But I don't know if that would work as these date styles have non-constant properties like the trailing one has different colors and the general one has a different one.
Maybe I can somehow preload pageviews in advance? I don't know if that would work when swiping fast.
Also, if it matters, currently I'm using Riverpod in my package for managing the calendar state.
So, if there is any way to improve the performance then please help me with that.
Current dirty solutions I found to this problem are:-
Setting viewportFraction: 0.99 in PageController of PageView. (It will help as it preloads the previous page and forward page). Suggested here #504337877.
Or use this preload_page_view package. Suggested here #636388237.
Currently, flutter doesn't support pre caching the PageView pages in advance but there are several issues about it on Github like this - #31191 , #45632 , and a closed pull request #42107 due to IOS related issue.
I failed to reuse the same widget in multiple places without rebuilding them.
And even if I succeed with the above I might fail to reuse states of child widgets of PageView as changing Pages means the whole child of PageView to be rebuilt as the index is new. So I cannot cache child widgets until I can reuse states in PageView.builder and GridView.Builder. A similar case for ListView is described in #49126.
If I'm wrong about the reusing same widget at multiple places then please correct me with a working small example as I'm more than happy to learn more. You can use this DartPad as starting point. The task is to bring the rebuild of customContainer from 42 to 1.
Not accepted as an answer as there could be more great answers to this in the future.
Related
I am trying to animate many widgets such as Text(), Image.asset() and other stuff when they are visible. I tried multiple libraries for checking visibilty of Widgets inside a SingleChildScrollView() but all solutions were either very complicated or it takes a lot of coding to achieve it for multiple widgets. The question that is most similar to mine is this, but it is simple for one or two widgets, but it will be messy for many Widgets. Can someone help me in achieving this requirement?
Edit:
I found that 'flutter_animate' depends on controllers, such as ScrollController, but no documentation about it was mentioned.
enter link description here
Consider the case that I have 3 adjacent list view with each list view having a sized widget of some height. Each list view has around 24 child items. I'm trying to scale the widget using onScaleUpdate in GestureDetector.
onScaleUpdate I want to change the height of each child item of all the 3 listviews.
Is rebuilding all child better or should I rebuild the whole widget?
As #Yeasin Sheikh pointed out, using ListView.builder is good because it builds only the needed children (the ones inside the screen and just a few ones outside as precaution). And as to actually answering your question, I'm no Flutter expert, but using ListView.builder I don't think it makes that much difference, Flutter is intelligent enough to solve this by itself.
I have two questions with and "if" regarding the first question. As the title says I know it's better to have one MaterialApp in an App in Flutter and making Scaffold widgets for screens. But in a situation like this App which I followed for learning purposes and it's really written well and very clean. but it uses "TabBarView" as a default home for the entire app. So if I want to add another screen like "LoginSreen" that's not part of the "TabBarView" it's not inheriting the "MaterialApp" widget features. So I have to add a "MaterialApp" widget independently for that screen.
So the question is, is it ok to have two "MaterialApp" widgets in a situation like this?
if yes does it affect any variables that's shared among the screens like "SharedPreference"? or what does it affect?
If it's a bad behavior to have two "MaterialApp" widgets to in an App, Then how can you get rid of the "NavScreen()" and implement the TabBarView in the screens, Because I have tried many ways and looked at many of open source projects like this they have "TabBarView" widget as the body and start of the project.
yes you can definitely have two mat apps. but its not recommended.
I have a PageView with a large amount of pages in my app. Each of the pages is very complex with a PageView and its own pages.
I'm new to Flutter and my first hunch is that it needs optimization. So within the build() function of the outmost PageView I check the index and only make full page for current, previous and the next page(I guess swipe animation needs current page and the page next to it built ahead). For other pages I just give it an empty Container().
Is this necessary and the right thing to do? I felt this is an obvious optimization that the Flutter should do, but I can't find any related discussion online. Any suggestions are appreciated!
Flutter's PageView is lazily calling itemBuilder you provided. For an index it's called only when the page is really needed and you don't need to do anything more. But for further improvements you can make your view hierarchy simpler and prevent unnecessary build method calls. Here you can read more about Performance best practices.
No, it's not. ListView, GridView, and widgets alike are already optimized to build and render only what is needed in the moment. You get a hint of that in the PageView.builder description :
Creates a scrollable list that works page by page using widgets that
are created on demand
I think the difference between a regular PageView and a PageView.builder is that PageView initializes all children at startup, while PageView.builder are initialized lazily.
I use GridView in my Flutter's app. Size my GridView is 30x4(with different widgets).
I need to update one widget in my gridView. I have two solutions and I need to choose the best.
Update all GridView. It is easy but I think this is not optimal (rebuild the entire grid for one change).
Update one widget. it is more complicated. but I know how to do it. This is a similar example.
what do you advise?