Difference between SliderThemeData().copyWith(...) and SliderTheme.of(context).copyWith(...) - flutter

I am new to flutter and was trying to change the slider style other than the default one. I found that it can be done using either SliderThemeData().copyWith(...) or SliderTheme.of(context).copyWith(...) and they are working exactly the same way. What is the difference between these two?
SliderTheme(
// data: SliderThemeData().copyWith(),
child: Slider(
activeColor: Color(0xFFEB1555),
inactiveColor: Color(0xFF8D8E98),
onChanged: (double value) {
},
value: 10
min: 10,
max: 100,
),
),

The difference is that if you customized the theme, you need to obtain it with SliderThemeData.of(context), the .of method looks up and returns the closest SliderTheme in the widget tree. You can read more about this here.
The SliderThemeData() generates a brand new SliderThemeData with the default values because you called the constructor with no additional parameters.
The .copyWith() method creates copy of this object but with the given fields replaced with the new values.

Related

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.

Rating becomes zero when i scroll down in 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.

Is it possible to pick out an item from a list of widget's based on the widget's value in dart / flutter?

I have a list of PopupMenuItem<T> as part of showMenu and I need to access the key for any given item when its clicked. When you click on an item, the showMenu will give you the selected value.
So I first gave each PopupMenuItem a key, which is part of a List:
[
PopupMenuItem<int>-[<'Small'>],
PopupMenuItem<int>-[<'Medium'>],
PopupMenuItem<int>-[<'Large'>]
]
OR put another way:
items: [
PopupMenuItem<int>(
key: ValueKey('Small'),
value: 10,
child: Text('10'),
),
PopupMenuItem<int>(
key: ValueKey('Medium'),
value: 20,
child: Text('20'),
),
PopupMenuItem<int>(
key: ValueKey('Large'),
value: 30,
child: Text('30'),
),
],
Now when you tap on an item, or select an item you get returned the value of that item, which is great, but I want to get access to the key, which is the Small, Medium and Large listed above.
So is there a way to dive into a given list and get the item based on its value. If I have the item or at least its position in the list I can then get the key by doing :
((items[1].key) as ValueKey<String>).value.toString();
/// 1 represents the position in the list.
///That is what I need to try to get, or just get the whole item somehow
I would suggest using UniqueKey() for the key. You can build a simple solution for your use case.
You can have a map to store the values with the respective strings.
Map<int,String> data ={10, 'Small', 20: 'Medium', 30: 'Large' }
Once you get the value from the tap, you pass the value to the map to get the respective string:
e.g. data[value]
simple and fast

onChange does not get called for the PrefChoice in Flutter

I am using the flutter pref library to create a settings page. The PrefChoice is used to show a drop down for language selection. The drop down shows the values properly. Issue is when we select anything from the drop down, the onChange method does not get called for some reason. Due to this we are not able to take action on the change in choice. Is there anything I am missing here?
PrefChoice<String>(
title: Text(AppLocalization.of(context, 'settings.language')),
pref: 'language_key',
items: const [
DropdownMenuItem(
value: LocaleConstants.LC_ENGLISH,
child: Text(LocaleConstants.ENGLISH)),
DropdownMenuItem(
value: LocaleConstants.LC_GERMAN,
child: Text(LocaleConstants.GERMAN))
],
onChange: (value) {
// This never gets called
log.d('Locale changed to - $value');
},
),

Can't add a function to onChanged property

I'm developing an app and my current task is to implement localization for several languages. Now that I've translated most of it, I need to create a button that I would nest in the app bar that would drop down and offer the different languages.
To that extent, I've followed this tutorial : https://www.youtube.com/watch?v=yX0nNHz1sFo&list=PLyHn8N5MSsgEfPAxCytQDPATDlHwpP5rE&index=3.
Now, since I plan on reusing this button for different pages, I created its own class, so far for good. But when comes time to add the onChanged property that would call the function responsible for language switching, it doesn't work. In fact, I can't call any function at all.
Here's the code snippet:
class LanguageButton extends StatelessWidget {
void changeLanguage(Language lang) {
print(lang.languageCode); //placeHolder
}
Widget build(BuildContext context) {
return DropdownButton(
underline: SizedBox(),
onChanged: (Language lang) {
changeLanguage(lang);
},
icon: Icon(
Icons.language,
color: Colors.white,
),
items: Language.languageList()
.map<DropdownMenuItem<Language>>((lang) => DropdownMenuItem(
value: lang,
child: Row(children: [
Text(lang.flag),
Text(lang.language),
])))
.toList(),
);
}
}
Which returns the error The argument type 'void Function(Language)' can't be assigned to the parameter type 'void Function(Language?)?'..
I've tried replacing by onChanged: ()=>print('hello') but it's still not working with a similar error message.
Any help is appreciated!
The onChanged method of a DropdownButton (see the documentation) is a ValueChanged<T?>?. That means it can itself be null (for example if you don't set it at all), but if you set it, you need to set it to a method with the signature void Function(T?). Your method does not confirm to that signature, because it does not allow nulls.
Change yourmethod to:
void changeLanguage(Language? lang) {
and either pass it directly:
onChanged: changeLanguage,
or make the anonymous method have a nullable parameter, too:
onChanged: (Language? lang) {
changeLanguage(lang);
},