What I have:
What I want:
I am using flutter_rating_bar
package and I want it to show the unselected containers as is instead of the default grey color and only want to change the color for the selected container.
As shown in the above pictures, instead of the grey boxes I want to display the remaining unselected containers preceding the selected ones as shown in the second picture.
Code:
RatingBar.builder(
initialRating: initialRatings,
itemCount: 5,
itemSize: 50,
itemPadding: EdgeInsets.symmetric(horizontal: containerWidth * 0.0077),
itemBuilder: (context, index) {
switch (index) {
case 0:
return Container(
width: ratingContainerWidth,
height: ratingContainerHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: knowledgeRating == 1
? const Color.fromRGBO(109, 44, 237, 1)
: const Color.fromRGBO(226, 243, 255, 1),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: Text(
'1',
textAlign: TextAlign.left,
style: TextStyle(
color: knowledgeRating == 1
? const Color.fromRGBO(255, 255, 255, 1)
: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'Inter',
fontSize: 16,
letterSpacing: 0.20000000298023224,
fontWeight: FontWeight.bold,
),
),
);
case 1:
return Container(
width: ratingContainerWidth,
height: ratingContainerHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: knowledgeRating == 2
? const Color.fromRGBO(109, 44, 237, 1)
: const Color.fromRGBO(226, 243, 255, 1),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: Text(
'2',
textAlign: TextAlign.left,
style: TextStyle(
color: knowledgeRating == 2
? const Color.fromRGBO(255, 255, 255, 1)
: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'Inter',
fontSize: 16,
letterSpacing: 0.20000000298023224,
fontWeight: FontWeight.bold,
),
),
);
case 2:
return Container(
width: ratingContainerWidth,
height: ratingContainerHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: knowledgeRating == 3
? const Color.fromRGBO(109, 44, 237, 1)
: const Color.fromRGBO(226, 243, 255, 1),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: Text(
'3',
textAlign: TextAlign.left,
style: TextStyle(
color: knowledgeRating == 3
? const Color.fromRGBO(255, 255, 255, 1)
: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'Inter',
fontSize: 16,
letterSpacing: 0.20000000298023224,
fontWeight: FontWeight.bold,
),
),
);
case 3:
return Container(
width: ratingContainerWidth,
height: ratingContainerHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: knowledgeRating == 4
? const Color.fromRGBO(109, 44, 237, 1)
: const Color.fromRGBO(226, 243, 255, 1),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: Text(
'4',
textAlign: TextAlign.left,
style: TextStyle(
color: knowledgeRating == 4
? const Color.fromRGBO(255, 255, 255, 1)
: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'Inter',
fontSize: 16,
letterSpacing: 0.20000000298023224,
fontWeight: FontWeight.bold,
),
),
);
case 4:
return Container(
width: ratingContainerWidth,
height: ratingContainerHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: knowledgeRating == 5
? const Color.fromRGBO(109, 44, 237, 1)
: const Color.fromRGBO(226, 243, 255, 1),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: Text(
'5',
textAlign: TextAlign.left,
style: TextStyle(
color: knowledgeRating == 5
? const Color.fromRGBO(255, 255, 255, 1)
: const Color.fromRGBO(0, 0, 0, 1),
fontFamily: 'Inter',
fontSize: 16,
letterSpacing: 0.20000000298023224,
fontWeight: FontWeight.bold,
),
),
);
default:
return Container();
}
},
onRatingUpdate: (rating) => setState(() {
knowledgeRating = rating;
}),
),
Unfortunately, this is not possible to do with flutter_rating_bar
. Checking the sources, if the itemBuilder
is being used there is a color filter applied to the child that blends the unratedColor
with the child widget. This unratedColor
is the source and it always wins because of the filter that is set to BlendMode.srcIn
.
This filter is not applied only if the itemBuilder
is null. But the only way to make it null is to use the default constructor and set the ratingWidget
that repeats the same for all ratings.
Fortunately, the source code is available and it's just a matter of forking it, removing the filter and pointing the fork in pubspec.yaml
to get the desired result like below:
pubspec.yaml
# ...
dependencies:
flutter_rating_bar:
git:
url: git://github.com/your_git_repo/flutter_rating_bar.git
ref: master
The changed widget without the color filter.
class _NoRatingWidget extends StatelessWidget {
_NoRatingWidget({
required this.size,
required this.child,
required this.enableMask,
required this.unratedColor,
});
final double size;
final Widget child;
final bool enableMask;
final Color unratedColor;
@override
Widget build(BuildContext context) {
return SizedBox(
height: size,
width: size,
child: FittedBox(
fit: BoxFit.contain,
child: child,
),
);
}
}