Imagine I have a Stack widget that only has 3 child widgets to display user profile. And I got multiple user profile data from the server. But I wanna display only the first 3 at the moment. Then, when I swipe first top child card widget, it has to be placed bottom of the Stack widget and widget data must be updated by 4th user data and so on. How to reuse child of Stack widget like shown in the GIF image below.
PS: Sorry for my English :) and any answer would be appreciated.
You can use a List to keep all your child widgets. Then, in the children of the Stack, pass only the first 3 elements of the List containing your child widget using <insert_your_list_name>.subList(0,3). Every swipe event on the child widget can then remove the first element of the List and append it to the back. Use setState to refresh your Stack.
Related
I have a page (stateful widget) that loads a child widget, this child widget is a grid, and it's loads another child widget a single grid item details.
on single grid item details, there is InkWell, and when onTap I Navigate to a new page.
the grid widget and the single grid item are both stateless widgets
when I go back from the new page using the back button I would like to update the previews page.
for example from the single grid item i have:
Navigator.pushNamed(
context,
SingleMoviePage.routeName,
arguments: movie,
).then((_){
var pressed = Provider.of<MoviesListProvider>(context,listen: false).listPageButtonPressed;
if (pressed) {
updateChanges();
}
});
I can update the page by passing the updateChanges function to grid widget and from the grid widget to the page.
but is there a better way to do it using provider ? or another way without the need to send the function from child to parent and from the parent to the grandparent ?
First of all you can do so by putting your data source in a ChangeNotifier and when it's updated you can notify all widgets that depend on it.
Another fast solution is to access the statful widget's state using a GlobalKey like this:
GlobalKey<yourStateFulWidget> myKey = GlobalKey()
and then access and edite the data like:
myKey.currentState!.someFunctionOrData();
note: to get a better understanding on how to do the first solution I recommend you to read the official example by the flutter team here:
https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple
So I have a widget (a) which contains an animated list and an empty list of widgets (SelectedWorkoutsList). Then after tapping any of the widgets in the list, I navigate to another widget (b) and pass the SelectedWorkoutsList which is still empty using Navigator. meanwhile in widget (b) i have the SelectedWorkoutsList) which is still empty and another List(WorkoutObjects) which contains widgets. After selecting any of its widgets the widget should be added to the SelectedWorkoutsList passed from Widget (a) and if the user tapped another time on the same widget it should be removed. All of this work perfectly, my problem is that after adding the widgets and pop back to the first widget (a) and then Navigate to (b) I still have that SelectedWorkoutsList but if I select a widget which I already selected before popping, it will add it as a duplicate while it should remove it.
I am using this if condition to check whether that widget was a already selected or not.
onTap: () {
if(!selectedWorkoutsList.contains(workoutObjects[index])) {
selectedWorkoutsList.add(workoutObjects[index]);
}else{
selectedWorkoutsList.remove(workoutObjects[index]);
}
print(selectedWorkoutsList.length);
},
So i have the workoutObjects List which contains Widgets and onTap, i check if the selectedWorkoutsList contains the widget that the user tapped from workoutObjects is yes it is removed is no it is added. it works fine except when I pop back then navigate again.
I am using seState. I think the problem is related to HashCode of the objects in the list (workoutsObject). Every time I load the widget the workoutObject are recreated in the init state with new hashcodes so when I compare widget with another widget in the selectedList it doesn't recognize that they are the same because of the difference in hashcodes. Is there a way to override the hashcode and compare two widgets using different method?
The problem here, is when you pop a page off, the previous page still has it's previous state. So, anything removed from the selected list will still be there on old page. What state management system are you using?
Like the topic I was wondering of there are any circumstances one should use the regular ListView instead of the ListView.builder in flutter, like if there are few items in a list could the ListView give better performance?
ListView has actually four different ways to use it , But let discuss ListView and ListView.builder
ListView : It has a children
property that takes a collection of static widgets. A ListView takes a small number of other widgets and makes it scrollable. Why a “small number”? Because this is designed to be a static list, one that you, the developer, simply types into the build() method
by hand.
ListView.builder : ListView’s alternative constructor, ListView.builder receives two
parameters, an itemCount and an ItemBuilder property that is a
function. This makes the ListView lazy-loaded. The itemBuilder function
dynamically creates children widgets on demand. As the user scrolls close
to the bottom of the list, itemBuilder creates new items to be scrolled into
view. And when we scroll something far enough off the screen, it is paged
out of memory and disposed of. Pretty cool.
Reference : taken from Rap Payne's Beginning App Development with Flutter (Great Book for beginners! , not an affiliate link).
official documentation for ListView .
ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. So if you just want to show some widgets below earch other and you need to scroll them you use ListView.
ListView.builder is a way of constructing the list where children’s (Widgets) are built on demand. However, instead of returning a static widget, it calls a function which can be called multiple times (based on itemCount ) and it’s possible to return different widget at each call.
I guess the simple answer you were looking for is:
Use ListView.builder whenever you iterate over an array of 'similar' elements.
Use ListView when items in your list are completely different from one another.
Think of ListView as scrollable Column
Let me start by explaining the problem. I have several buttons which are created based on data I'm getting from a server. On each button click I need to create and display a widget which will present me some data (this widget is also built dynamically). The state of this widget has to be preserved during the lifetime of the app. (for example if I click another button and show a different widget, I need to be able to click on the first button and show the first widget in its preserved state). Number of buttons can also be changed during the app lifetime.
I tried using IndexedStack to achieve this, but when the number of buttons is changed I need to add "pages" to IndexedStack, therefore I need to recreate a new IndexedStack which will have some of my old widgets, so I pull widgets from a List or create new ones if needed. This works great, except Flutter calls dispose() method on my widgets which are stored in the list. I tried using the AutomaticKeepAliveClientMixIn but it didn't help.
I'm guessing this has something to do that the widgets get detached from the parent, but when I reattach them to new parent (new Indexed stack) Flutter doesn't figure out this properly.
Any ideas?
Try to store data to local storage or sqlite for persistence data.
I'm making a screen with comments section that has comments & their sub comments.
I use ScopedModel for managing state of the screen.
The data for comments is in a List<-model->
and for subcomments are inside the model->List<-model->.
this data is in ScopedModel.
I build a sliverList with SliverChildBuilderDelegate so it builds only widgets that are on screen.
Every comment (current_comment) has a reply button, that, after typing, adds a comment model at the end of (current_comment)model-> List<-model->
and calls notifyListener() on the ScopedModel
Now the newly added subcomment has a tag that identifies it as a new comment.
What I want:
I want that the screen scrolls to the newly added subcomment.
What I tried:
Since the newly added subcomment can be identified by a tag, I add a GlobalKey to that comment widget when its built. and then after build is complete, I scroll to that position using the offset obtained from GlobalKey added to it.
My Problem :
Since the SliverList builds elements which are visible to screen only, the newly added comment is far below the parent comment (because reply comment button is on the parent comment only) and isn't built yet. so the builder hasn't attached the GlobalKey to it yet.
Now, how do I auto-scroll to it?
Since key isn't attached to it yet, how do I locate its position & scroll to it?
Suggest me a way to either build all elements of the Sliverlist at once so the key may be attached to the element or another strategy so to auto-scroll to the newly added comment.
First solution is to set shrinkWrap property as true to the listview so it renders all children at once, and hence GlobalKey is assigned to it.
Second solution is to use a column instead, which will lead to rendering all children at once.
Both solutions are not suitable when there are too many children.