Open In App

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:



To build the above application follow the below steps:

Adding the Dependency:

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



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:




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:




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:




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:




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:




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:




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:


Article Tags :