Open In App

Flutter – Customizable Ratings bar

Improve
Improve
Like Article
Like
Save
Share
Report

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




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,
            ),
          ),
        ),
      ),


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




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);
   },
);


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




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


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




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,
                     ),
                   ],
                 ),


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




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();
   }
 }


Complete Source Code:

Dart




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,
      ),
    ],
  );
}


Output:



Last Updated : 15 Feb, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads