Rating becomes zero when i scroll down in flutter - flutter

I am using flutter rating bar package to give feedback to particular section then rating becomes back to 0. ho w can i persist the given rating constant .
Here is the screenshot of the app ...
RatingBar(
initialRating: 0,
direction: Axis.horizontal,
allowHalfRating: false,
itemCount: 5,
ratingWidget: RatingWidget(
full: const Icon(Icons.star,
color: Colors.orange),
half: const Icon(
Icons.star_half,
color: Colors.orange,
),
empty: const Icon(
Icons.star_outline,
color: Colors.orange,
)),
onRatingUpdate: (value) {}),

i think its a flutter behavior. in case we have much children on listview, then when we scrolldown, the widget that out of screen will marked as dirty widget.
then when we back scroll again , flutter will rebuild the widget.
Flutter already provide the solution here called
Destruction mitigation
you have to store the rating value to the object state. so when the widget get re-build , the value will automatically set from stored value.
other simple solution (not recomended)
you can extend the cache of listview.
ListView(
shrinkwrap: true,
cacheExtent : 99999999
children: [
RatingWidget(),
],
here the explanation to the chaceExtent
or another question in stackoverflow
What exactly does cacheExtent property in ListView.Builder do?

In onRatingUpdate save its value
onRatingUpdate :(val) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt("teacherConcept", val);
}
Then in initstate get the value like
SharedPreferences prefs = SharedPreferences.getInstance();
int teacherConcept = prefs.get("teacherConcept", true);
Assign this teacher concept as the initial value of the ratingbar

That is because you have set initialRating to 0. So when you scroll down and come back up the whole widget rebuilds meaning for performance purposes it does not keep it in memory and the ratings get reset. So, what you can do is set the ratings set by the user into a variable through the onRatingUpdate and pass that variable into intitialRating
Map<String, int> ratings={'subjectClear':0, 'subjectVarieties':0}; // add other 8 as well
...
...
initialRating: ratings['subjectClear'],
onRatingUpdate: (value){
rating['subjectClear'] = value;
},
...
Still this data will be erased after the user restarts the app. So what you can do is store the data in a database and when the user returns substitute the values to the necessary variables.

Related

Flutter: setState not updating screen in Async function

From initState() I call setDefaults(), which builds a Person object, having done this execution should return to initState which calls getPrefs(), an async function.
#override
void initState() {
super.initState();
setDefaults();
getPrefs();
}
getPrefs calls SharedPreferences.instance() and retrieves some data from prefs - hooyah!
This is compared with some fields of the Person object, finally setState() is called to update the screen with a Tile colour, and to render a Banner widget if (usersTile == true).
This never happens, setState never updates the screen. I don't know why.
Future<void> getPrefs() async {
prefs = await SharedPreferences.getInstance();
List<String> neighbourProfilesDownloaded = prefs!.getStringList("downloadedPersonProfiles") ?? [];
neighbourProfilesDownloaded.add(widget._person!.firebaseId!);
prefs!.setStringList("downloadedPersonProfiles", neighbourProfilesDownloaded);
usersTile = widget._person!.firebaseId == prefs!.getString("firebaseId") ?? "";
setState(() {
tileColor = usersTile ? Colors.grey.shade900 : Color(0xFF462c22);
usersTile;
});
}
This question has been asked before. I've tried looking at other solutions on StackOverflow, so far as I can see I'm already following their proposed solutions, to await the asynchronous call then setState after it. And none of the proposed answer have been marked correct anyway.
I've tried assigning the value of usersTile inside setState, no difference.
The Tile colour does sometimes work, however not on screen load. If I scroll down the Tile list, swiping the usersTile out of the viewport, then swiping back up to return to it, I find that DOES update the Tile's colour and Banner. Indicating the Tile property assignments are working but setState is not.
This is not satisfactory, it screams buggy to the user.
I know this can work, because I have another class, another ListView screen in my app which seems to reliably update the screen on load. I've studied the control flow on that screen and can't see how it's different. Quite the boggle.
This is the Card Widget, with properties I want to adjust, from build()
return Card(
margin: EdgeInsets.fromLTRB(0, 4, 0, 4),
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
color: tileColor,
key: ValueKey(widget._person!.firebaseId! + "LoaningTileCard"),
child: usersTile ? Banner(
message: "YOURS",
location: BannerLocation.topEnd,
color: Colors.red,
child: CardContentWidget)
: CardContentWidget);
I think CardContentWidget uses Card in build method, Card has default background color as Colors.white by using CardTheme.of(context).
You may have to reset with transparent or user Container instead.

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

flutter swiper package avoid to swipe to next position, it stay on first

I have a working code before null safety flutter upgrade. But after the migration, the same code doesn't work.
I had a simple horizontal swipe card, but now something force the swipe to stay on the first position or rebuild. When I remove didChangeDependencies (function I use to load when data change) the swipe is OK. I think when data is load by didChangeDependenciesit refresh new Swiper.children( and force to return always to first index position.
But I can't do without didChangeDependencies, how can I do ?
Here is the package https://pub.dev/packages/flutter_swiper_null_safety/example
Here is my code:
#override
void didChangeDependencies() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
}
new Swiper.children(
viewportFraction: 0.8,
scale: 0.6,
autoplay: false,
loop: false,
control: new SwiperControl(
size: 25.0,
color: Color(0xffff9a7b),
disableColor: Colors.transparent ,
padding: const EdgeInsets.all (5.0),
),
children: <Widget>[
Card1()
Card2()
Card3()
]
Usually you would need to have a controller or index saved in the state that could hold the state of the downstream widget so on rebuilds the state stayed the same.
After looking at this package it doesn't appear you can pass in an Index or Controller to the widget so it will be rebuilt any time something above it on the stack is rebuilt.
Is it possible to reorganize your page so that the swiper is not under it in the stack?

Flutter: a dismissed dismissible widget is still part of the tree

I am building a fitness app (image here: Fitness App example
) where the user can log their sets. I am having an issue when using the dismissible widget inside of my app. The swipe to delete functionality sends the following exception: a dismissed dismissible widget is still part of the tree
When swiping to delete a single set, I still need to retain the information the user has put into the other sets. I believe this is an issue with the key, however I've already tried UniqueKey() (which resets all of the other input fields) and the example below.
How can I remove a single set using dismissible and still retain the rest of the users data for the other sets? Thanks.
late List count = [0];
ListView.builder(
shrinkWrap: true,
itemCount: _count.length,
itemBuilder: (context, index) {
// Create a new variable to display the set
int setNumber = index + 1;
return Dismissible(
key: ValueKey(_count[index]),
background: _swipeStyle(),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
_count.removeAt(index);
});
},
child: Row(
children: [
Expanded(flex: 1, child: Text('Set $setNumber')),
Expanded(flex: 2, child: _buildWeight(index)),
const SizedBox(
width: 24.0,
),
Expanded(flex: 2, child: _buildReps(index)),
],
),
);
},
),
Since the Key is based on a list of ints, maybe there are repeated keys? In that case the framework won't know which item was removed and will trigger the error you just found.
A possible solution would be to assign an unique ID to each item, that way you will never have repeated keys.
Try replace key: ValueKey(_count[index]) with UniqueKey()

How to create recommended ListView in flutter and fire store

There's a way to create a recommended from user ListView using fire base and flutter...
For example I have a list of data in firebase that I am fetching them from firebase as I show them in the data list screen, and I have a list of recommended list view from user for example the clicked data item from user something shows like the below image:
To be more specific how figure if the data was viewed by user or not?
There's a way or docs to do something like this?
In case your intention is to provide some kind of "user likes" functionality.
You can create Provider of ChangeNotifier with Provider package at root (for example) and store Set<YourShopItem> there.
Then expose methods like add(YourShopItem item) and remove(YourShopItem item) on this ChangeNotifier which should add and remove items from your set and call notifyListeners() every time you call this method.
Then when you need to determine if your item is liked just obtain your ChangeNotifier and check if item is in set. Your widgets is gonna be updated every time add or remove methods are called because of their subscription to ChangeNotifier through Provider.
In case your intention is to track visibility of item.
You can use visibility detector package to track whether certain widget is visible. You can subscribe to certain widget and when it's shown, a callback is gonna be fired. So you should wrap every widget of your list into VisibilityDetector widget and save that your item was viewed.
Something like that should do the job:
final List<String> entries = <String>['A', 'B', 'C'];
final List<int> colorCodes = <int>[600, 500, 100];
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return VisibilityDetector(
onVisibilityChanged: (VisibilityInfo info) {
if (info.visibleFraction == 1) {
ON_YOUR_ITEM_IS_VISIBLE_FUNCTION();
}
},
child: Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
),
);
}
);
Also refer to this: https://stackoverflow.com/a/63577928/13737975.