Flutter – Customizable Ratings bar

Rating Bar as the name suggests is used to rate content inside the application. More or less all applications use them either to gate user feedback on their application or to get a rating for content hosted by the application. Applications like IMDB use them to rate movies and Television series where apps like and Uber use them to get feedback on their services from the customer.

In this article we will build a simple app with the following features:

  • A horizontal Rating bar
  • A switch to make all rating bars above go right to left
  • A switch to make the rating bars vertical
  • Three different modes to change the Icon of the first rating bar

To build the above application follow the below steps:

  • Add the dependency to the pubspec.yaml file
  • Import the dependency to the main.dart file
  • Use the StatefulWidget to give structure to the application
  • Add the vertical rating bar
  • Add switch to change the alignment of the rating bars from right to left (RTL)
  • Add a switch to change the alignment of the rating bar from horizontal to vertical
  • Add 3 different modes that change the UI Icons.

Adding the Dependency:

To add the dependency to the pubspec.yaml file the following image can be followed:

dependency



Importing the Dependency:

To import the flutter_rating_bar dependency to the main.dart file, use the following:

import 'package:flutter_rating_bar/flutter_rating_bar.dart';

Structuring the application: 

A StatefulWidget can be used to give the app an appbar and a body to hold content as shown below:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
  
class _MyAppState extends State<MyApp> {
  var _ratingController = TextEditingController();
  double _rating;
  int _ratingBarMode = 1;
  bool _isRTLMode = false;
  bool _isVertical = false;
  IconData _selectedIcon;
  
  @override
  void initState() {
    _ratingController.text = "3.0";
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.green,
        appBarTheme: AppBarTheme(
          textTheme: TextTheme(
            title: Theme.of(context).textTheme.title.copyWith(
              color: Colors.white,
            ),
          ),
        ),
      ),

chevron_right


Designing a vertical rating Bar:

A simple rating bar can be called upon from the flutter_rating_bar package by calling the RatingBar widget as shown below:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

RatingBar(
   initialRating: 3,
   minRating: 1,
   direction: Axis.horizontal,
   allowHalfRating: true,
   itemCount: 5,
   itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
   itemBuilder: (context, _) => Icon(
     Icons.star,
     color: Colors.amber,
   ),
   onRatingUpdate: (rating) {
     print(rating);
   },
);

chevron_right


Adding A RTL switch:

At this stage, we will add a switch that can change the alignment of the rating bar from left to right, to right to left. It can be done by using the MainAxisAlignment as MainAxisAlignment.center and calling the _isRTL mode as shown below:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

mainAxisAlignment: MainAxisAlignment.center,
                   children: <Widget>[
                     Text(
                       'Switch to RTL Mode',
                       style: TextStyle(
                         fontWeight: FontWeight.w300,
                       ),
                     ),
                     Switch(
                       value: _isRTLMode,
                       onChanged: (value) {
                         setState(() {
                           _isRTLMode = value;
                         });
                       },

chevron_right


Adding a Vertical alignment switch:

At this stage, we will add a switch that can change the alignment of the rating bar from left to right, to right to left. It can be done by using the MainAxisAlignment as MainAxisAlignment.center and calling the _isVertical mode as shown below:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

mainAxisAlignment: MainAxisAlignment.center,
                   children: <Widget>[
                     Text(
                       'Switch to Vertical Bar',
                       style: TextStyle(
                         fontWeight: FontWeight.w300,
                       ),
                     ),
                     Switch(
                       value: _isVertical,
                       onChanged: (value) {
                         setState(() {
                           _isVertical = value;
                         });
                       },
                       activeColor: Colors.amber,
                     ),
                   ],
                 ),

chevron_right


Adding Modes to the Rating bar:

In this application, we will be adding 3 Mode and on the selection of each mode the rating bar Icon will change. We will be using the switch() function to assign the cases to modes and assign icons to the same as shown below:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

Widget _ratingBar(int mode) {
   switch (mode) {
     case 1:
       return RatingBar(
         initialRating: 2,
         minRating: 1,
         direction: _isVertical ? Axis.vertical : Axis.horizontal,
         allowHalfRating: true,
         unratedColor: Colors.amber.withAlpha(50),
         itemCount: 5,
         itemSize: 50.0,
         itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
         itemBuilder: (context, _) => Icon(
           _selectedIcon ?? Icons.star,
           color: Colors.amber,
         ),
         onRatingUpdate: (rating) {
           setState(() {
             _rating = rating;
           });
         },
       );
     case 2:
       return RatingBar(
         initialRating: 3,
         direction: _isVertical ? Axis.vertical : Axis.horizontal,
         allowHalfRating: true,
         itemCount: 5,
         ratingWidget: RatingWidget(
           full: _image('assets/heart.png'),
           half: _image('assets/heart_half.png'),
           empty: _image('assets/heart_border.png'),
         ),
         itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
         onRatingUpdate: (rating) {
           setState(() {
             _rating = rating;
           });
         },
       );
     case 3:
       return RatingBar(
         initialRating: 3,
         direction: _isVertical ? Axis.vertical : Axis.horizontal,
         itemCount: 5,
         itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
         itemBuilder: (context, index) {
           switch (index) {
             case 0:
               return Icon(
                 Icons.sentiment_very_dissatisfied,
                 color: Colors.red,
               );
             case 1:
               return Icon(
                 Icons.sentiment_dissatisfied,
                 color: Colors.redAccent,
               );
             case 2:
               return Icon(
                 Icons.sentiment_neutral,
                 color: Colors.amber,
               );
             case 3:
               return Icon(
                 Icons.sentiment_satisfied,
                 color: Colors.lightGreen,
               );
             case 4:
               return Icon(
                 Icons.sentiment_very_satisfied,
                 color: Colors.green,
               );
             default:
               return Container();
           }
         },
         onRatingUpdate: (rating) {
           setState(() {
             _rating = rating;
           });
         },
       );
     default:
       return Container();
   }
 }

chevron_right


Complete Source Code:

Dart

filter_none

edit
close

play_arrow

link
brightness_4
code

import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
  
void main() => runApp(MyApp());
  
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
  
class _MyAppState extends State<MyApp> {
  var _ratingController = TextEditingController();
  double _rating;
  int _ratingBarMode = 1;
  bool _isRTLMode = false;
  bool _isVertical = false;
  IconData _selectedIcon;
  
  @override
  void initState() {
    _ratingController.text = "3.0";
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.green,
        appBarTheme: AppBarTheme(
          textTheme: TextTheme(
            title: Theme.of(context).textTheme.title.copyWith(
              color: Colors.white,
            ),
          ),
        ),
      ),
      home: Builder(
        builder: (context) => Scaffold(
          appBar: AppBar(
            title: Text('GeeksForGeeks'),
            backgroundColor: Colors.green,
          ),
          body: Directionality(
            textDirection: _isRTLMode ? TextDirection.rtl : TextDirection.ltr,
            child: SingleChildScrollView(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  SizedBox(
                    height: 40.0,
                  ),
                  _heading('Rating Bar'),
                  _ratingBar(_ratingBarMode),
                  SizedBox(
                    height: 20.0,
                  ),
                  _rating != null
                      ? Text(
                    "Rating: $_rating",
                    style: TextStyle(fontWeight: FontWeight.bold),
                  )
                      : Container(),
                  Row(
                    children: [
                      _radio(1),
                      _radio(2),
                      _radio(3),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Switch to Vertical Bar',
                        style: TextStyle(
                          fontWeight: FontWeight.w300,
                        ),
                      ),
                      Switch(
                        value: _isVertical,
                        onChanged: (value) {
                          setState(() {
                            _isVertical = value;
                          });
                        },
                        activeColor: Colors.amber,
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Switch to RTL Mode',
                        style: TextStyle(
                          fontWeight: FontWeight.w300,
                        ),
                      ),
                      Switch(
                        value: _isRTLMode,
                        onChanged: (value) {
                          setState(() {
                            _isRTLMode = value;
                          });
                        },
                        activeColor: Colors.amber,
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
  
  Widget _radio(int value) {
    return Expanded(
      child: RadioListTile(
        value: value,
        groupValue: _ratingBarMode,
        dense: true,
        title: Text(
          'Mode $value',
          style: TextStyle(
            fontWeight: FontWeight.w300,
            fontSize: 12.0,
          ),
        ),
        onChanged: (value) {
          setState(() {
            _ratingBarMode = value;
          });
        },
      ),
    );
  }
  
  Widget _ratingBar(int mode) {
    switch (mode) {
      case 1:
        return RatingBar(
          initialRating: 2,
          minRating: 1,
          direction: _isVertical ? Axis.vertical : Axis.horizontal,
          allowHalfRating: true,
          unratedColor: Colors.amber.withAlpha(50),
          itemCount: 5,
          itemSize: 50.0,
          itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
          itemBuilder: (context, _) => Icon(
            _selectedIcon ?? Icons.star,
            color: Colors.amber,
          ),
          onRatingUpdate: (rating) {
            setState(() {
              _rating = rating;
            });
          },
        );
      case 2:
        return RatingBar(
          initialRating: 3,
          direction: _isVertical ? Axis.vertical : Axis.horizontal,
          allowHalfRating: true,
          itemCount: 5,
          ratingWidget: RatingWidget(
            full: _image('assets/heart.png'),
            half: _image('assets/heart_half.png'),
            empty: _image('assets/heart_border.png'),
          ),
          itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
          onRatingUpdate: (rating) {
            setState(() {
              _rating = rating;
            });
          },
        );
      case 3:
        return RatingBar(
          initialRating: 3,
          direction: _isVertical ? Axis.vertical : Axis.horizontal,
          itemCount: 5,
          itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
          itemBuilder: (context, index) {
            switch (index) {
              case 0:
                return Icon(
                  Icons.sentiment_very_dissatisfied,
                  color: Colors.red,
                );
              case 1:
                return Icon(
                  Icons.sentiment_dissatisfied,
                  color: Colors.redAccent,
                );
              case 2:
                return Icon(
                  Icons.sentiment_neutral,
                  color: Colors.amber,
                );
              case 3:
                return Icon(
                  Icons.sentiment_satisfied,
                  color: Colors.lightGreen,
                );
              case 4:
                return Icon(
                  Icons.sentiment_very_satisfied,
                  color: Colors.green,
                );
              default:
                return Container();
            }
          },
          onRatingUpdate: (rating) {
            setState(() {
              _rating = rating;
            });
          },
        );
      default:
        return Container();
    }
  }
  
  Widget _image(String asset) {
    return Image.asset(
      asset,
      height: 30.0,
      width: 30.0,
      color: Colors.amber,
    );
  }
  
  Widget _heading(String text) => Column(
    children: [
      Text(
        text,
        style: TextStyle(
          fontWeight: FontWeight.w300,
          fontSize: 24.0,
        ),
      ),
      SizedBox(
        height: 20.0,
      ),
    ],
  );
}

chevron_right


Output:




My Personal Notes arrow_drop_up


If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :

Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.