How to change the color of an Icon through boolean return in Flutter?
I have a method that queries books that are favored in the Firestore database, the book page has a star icon in black color, I use isfavorite method to query if the open book is favored by the user or not, if it is it should return true and change the icon color to yellow but the change does not happen.
The updateFavorite method works perfectly by adding and removing the favorite book from the bank by tapping the icon, only his color I can't set up.
InkWell(
child: Icon(
Icons.star,
size: 30,
color: isFavorite == true ? Colors.yellow
: Colors.black,
),
onTap: (){
model.updateFavorite(model.getUserId(), document.documentID);
},
),
==============
Future<bool> isFavorite() async{
firebaseUser = await _auth.currentUser();
DocumentSnapshot favoritesRef = await Firestore.instance.collection("users")
.document(firebaseUser.uid).get();
if(favoritesRef.data["favorites"].contains(document.documentID)){
print("SIM");
return true;
}
else {
print("NÃO");
return false;
}
}
==============
Future<bool> updateFavorite(Future<DocumentReference> uid, String bookId) async{
firebaseUser = await _auth.currentUser();
DocumentReference favoritesRef = Firestore.instance.collection("users")
.document(firebaseUser.uid);
return Firestore.instance.runTransaction((Transaction tx) async{
DocumentSnapshot postSnapshot = await tx.get(favoritesRef);
if(postSnapshot.exists){
if(!postSnapshot.data["favorites"].contains(bookId)){
await tx.update(favoritesRef, <String, dynamic>{
"favorites": FieldValue.arrayUnion([bookId])
});
// Delete de bookId from Favorites
} else {
await tx.update(favoritesRef, <String, dynamic>{
"favorites": FieldValue.arrayRemove([bookId])
});
}
}
}).then((result){
print(firebaseUser.uid);
print(bookId);
return true;
}).catchError((error){
print("Error: $error");
print("DEU RUIM");
return false;
});
}
1 answers
Well, as they have already commented, apparently you are not controlling the state of your application correctly, so after executing your method updateFavorite()
you are not warning Flutter that it should render your Icon again.
I noticed that you use 2 Futures, 1 to update the favorite, and another on the icon to actually check whether or not it is a favorite to render the color. In this case you can also use a FutureBuilder , widget well bacaninha which always updates when Future has its result. I created an example for you to have idea of the operation and adapt for its use.
Main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
YourBusiness yourBusiness = new YourBusiness();
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FutureBuilder(
future: yourBusiness.isFavorite(''),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
bool isFavorite = false;
if(snapshot.hasData) { // Verificar se o Future possui dado
isFavorite = snapshot.data;
}
return Icon(Icons.ac_unit,
size: 160.0,
color: isFavorite ? Colors.greenAccent: Colors.black,
);
}
),
RaisedButton(
child: Text('CHANGE COLOR'),
onPressed: () {
yourBusiness.updateFavorite('').then((bool) {
setState(() {});
});
},
),
RaisedButton(
child: Text('SET STATE'),
onPressed: () {
setState(() {});
},
)
],
)
],
),
)
);
}
}
Your_business.dart
class YourBusiness {
bool _isFavorite = false;
Future<bool> isFavorite(String yourParams) async {
await Future.delayed(Duration(seconds: 1));
// DO YOUR STUFF HERE
return _isFavorite;
}
Future<bool> updateFavorite(String yourParams) async {
await Future.delayed(Duration(seconds: 1));
// DO YOUR STUFF HERE
_isFavorite = true;
return _isFavorite;
}
}
Result
Keep in mind that every time you update the state of this Widget, the Future of the Icon will run again, which is not a good idea, but you can define other strategies, then it goes from Logic that you want to assemble in your App.
I recommend using some pattern for application state control, such as Bloc.