I want to put objects randomly, then on new screen I want player to put widgets as before. How can I do that?
What widgets/ packages would make it easy?
Say you have a list of objects in your widget, that is displayed in order by the build function.
You could use initState to shuffle your list the first time your widget loads, using a shuffle function such as the one provided in this other StackOverflow answer.
List<MyItem> items = [MyItem('first'), MyItem('second'), MyItem('third')];
#override
initState() {
items = shuffle(items);
super.initState();
}
Then when going to the next screen, you can pass the shuffled version of items, and use that as the 'correct' solution.
It's a bit difficult to see what exactly you're looking for as no code was provided, but hopefully this gives you some inspiration for your actual problem.
Try to use CustomPainter and Canvas
so can access Offset
Related
I'm building a chat app and I want to achieve a ListView() that loads up like its reverse property is set to true i.e showing the end of the ListView on build. The reason I don't want to set the reverse property to true is because, if the items in the ListView do not fill up the screen, they are aligned to the bottom (cannot use shrinkWrap because of performance), and also because it reverses the order of the items and to show new elements at the bottom of the list, I'd need to use a spread operator and I'm worried about performance since the Map from which I render from can grow significantly.
I have also tried using the ScrollController's jumpTo method inside a SchedulerBinding.instance!.addPostFrameCallback but the user can see the scrolling and
it also causes it to jump like it's attempting to scroll beyond what is contained in the ListView. I have also used ScrollablePositionedList and set the index to which I want to scroll, but this jumps also.
Is there any way I can achieve my aim without any drawbacks visually or performance-wise?
You have the correct idea: in the initState, jump to the end. The end of the list can be obtained from position.maxScrollExtent. When done correctly, this does not create any visual or performance drawbacks. For example:
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_controller.jumpTo(_controller.position.maxScrollExtent);
});
}
The _controller should be the ScrollController passed to the list.
I am facing problem to re-render the page when a variable changes in one class/widget (both parent and child widgets are stateful classes).
Here is how it goes:
I have three buttons in one class which changes a variable state (foodCategory).
int foodCategory = 0;
// down in the elevated button body - i am updating the variable
setState(() {
foodCategory = 1;});
While in the other widget, i am using this variable to perform certain actions:
for (var item in foodItems.values.elementAt(foodCategory))
GestureDetector(........ and so on...
However in the second snippet, the widget dose not know if there has been a change and it is not calling the buildcontext again...
I am not sure how to overcome this problem. I have tried valuelistenablebuilder but in vain. Maybe i dont know how to use it in the loop (i am using foodcategory as an int (iterator)).
it happned to be that i was sing valuelistenable builder in a wrong way.
It is easy. Just mark the variable and changes as valueNotifier. In my case, i needed to mark foodCategory as a valueNotifer.
Than, i needed to wrap the Widget (in my case column widget) as ValueListenableBuilder. This solved my issue.
I'm new to Flutter and I'm trying to build a chat application and I've watched several tutorials. To view the chat messages list/history, almost every tutorial is doing something like this: (I'm shortening the code to get to the point)
List<Widget> messages = api.listOfMessages();
return Column(children: messages);
Now every time there's a new message, messages is updated and the column is re-built. I gotta say the word "rebuild" sounds an expensive procedure to me. Say 2 users have been chatting 500 lines. Now every time a new message is coming, 500 lines are getting rebuilt over an over.
I thought about putting an empty widget at the end of the list. So when a new message arrives, I just insert it to that empty widget and have that to rebuild only:
List<Widget> messages = api.listOfMessages();
return Column(children: [...messages, EmptyWidgetForNewMessage()];
But that looks like a hack and will cause a lot of nested widgets, because every new message must also insert another EmptyWidget etc...
How can I avoid rebuilding previous messages and only insert the new one to the view? (or rebuilding the entire list is not that big a deal?)
You can use sliver widget to build the messages that are visible in viewport(or within cacheExtent).
Like ListView.build, ListView.separated, from the doc of ListView.build:
if the list view's children are
created in advance, or all at once when the [ListView] itself is created,
it is more efficient to use the [ListView] constructor. Even more efficient, however, is to create the instances on demand using this constructor's itemBuilder callback.
Also, we will not fetch all messages from server at once. Instead we will fetch them in batches with query like ?page=1&size=20.
Note: There is a known issue with this widget, avoid using shrinkWrap: true if possible. See this issue
couple of improvements that you could target
Use ListView builder constructor instead of the column, only the children widget that are currently visible in the screen will be rendered whereas in Column widget all of its children will be rendered. Also ListView should be your preferred widget, because the Column widget is not scrollable, and there are chances of overflow exception, if the message list length is huge.
Use const constructor for all type of widgets returned by api.listOfMessages(), this will allow the compiler to reuse any rendered widget, meaning every time when a state change happens(in you case arrival of a new message) the entire tree is not re-rendered, the renderer will have the luxury of re using previously built message widget.
These two suggestions should take care of any performance bottlenecks, in short we would be rendering only the visible children widgets with ListView and we will be re reusing already rendered widget with the help of const constructor.
I am currently making a simple POS app. As I was writing the code for adding a new item to the menu. I thought about the potential number of listeners that would be present on the page. I decided to go with multiple, individual TextFormField since the user can decide how many additional toppings they want to offer; each additional topping will have their own TextFomField to enter the relevant data. Sample Structure of the TextFormField (written inside of initState())
Each TextFormField saves its value to a variable on every focus change. My worry is that if they decide to add 5 toppings then I would have 5 active listeners. So, I would like to know what is a good limit to the number of listeners I should have and is there a better solution to my problem (instead of using focus changes).
You don't have to worry about a a couple of listeners. 5 is not a relevant number by any means. If you add listeners, make sure you dispose of them when the widget is removed.
Make sure to have this in your Widget for each FocusNode / Controller that has listeners.
#override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
_nameFocusNode.dispose();
super.dispose();
}
Another way is to use the onChanged property.
You could use it like this
TextFormField(onChanged: _updateName);
I am creating a Flutter app using the Flip Card Package. I would like to be able to flip a card and see a randomly selected image. Example: Flash cards, one side is a static image, I flip it to see a picture of a dog. I then tap again and it flips to back to the static image. I tap again, and I see a picture of a cat, etc...
I was able to get it all set up. The card flips back and forth but it is not randomly selecting a new card unless I restart the build after each flip. So, I am missing a piece somewhere that tells the app to pick again. Your help would be super appreciated!
Flip Card description https://pub.dev/packages/flip_card
snippet of code
Just as a tip as it seems you are new to SO - please post the code as text so that we can paste is in an IDE and try to run it. As an image its much harder to replicate your issue. Just a tip for going forward. Otherwise, welcome to SO!
So for your issue, I am not certain exactly why since I cannot see the entire context within that snippet BUT i suspect its because the card doesn't know it needs to rebuild since its just being replaced by another image but it doesn't know its a new image.
You can create a Widget class thats stateless and pass in the path. The Key change will ensure that the widget gets rebuilt:
The Widget class:
class FlipCardDetails extends StatelessWidget {
final String imagePath;
const FlipCardDetails({Key key, #required this.imagePath}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Image.asset(
this.imagePath,
key: ValueKey<String>(imagePath),
)
],
)
);
}
}
Then in your main code where it says:
back: Container(child: _cardDetails()),
You can replace this with:
back: FlipCardDetails(imagePath: <Provide the image path>);
You can create a key based on the image path itself like so:
key: ValueKey<String>(imagePath)
This all would only work if there is a function you can run when the person clicks the card that would flip the card. That way you can run your randomizer and provide the image path to the widget.
Instead if you can't and the widget needs to calculate its own random path, then make it stateful, and on initState change the image path. That should work as well.
Without more context I can't really be sure if this is right or which solution works better. Let me know and I can to advise more.
I think that the problem is that your calling the 'Random' function only once when initializing your card. Try adding a function in which you call the Random function to change your '_random' and your 'element' and call it every time the card is flipped.You can do that by using the 'onFlipDone' function field of the FlipCard.