Flutter: barra de calificaciones personalizable

La barra de calificación, como sugiere su nombre, se usa para calificar el contenido dentro de la aplicación. Más o menos todas las aplicaciones las usan para obtener comentarios de los usuarios sobre su aplicación o para obtener una calificación del contenido alojado por la aplicación. Aplicaciones como IMDB las usan para calificar películas y series de televisión, mientras que aplicaciones como Uber las usan para obtener comentarios sobre sus servicios por parte del cliente.

En este artículo construiremos una aplicación simple con las siguientes características:

  • Una barra de calificación horizontal
  • Un interruptor para hacer que todas las barras de calificación de arriba vayan de derecha a izquierda
  • Un interruptor para hacer que las barras de calificación sean verticales
  • Tres modos diferentes para cambiar el ícono de la primera barra de calificación

Para construir la aplicación anterior, siga los pasos a continuación:

  • Agregue la dependencia al archivo pubspec.yaml
  • Importe la dependencia al archivo main.dart
  • Usa el StatefulWidget para dar estructura a la aplicación
  • Agregar la barra de calificación vertical
  • Agregue un interruptor para cambiar la alineación de las barras de clasificación de derecha a izquierda (RTL)
  • Agregue un interruptor para cambiar la alineación de la barra de calificación de horizontal a vertical
  • Agregue 3 modos diferentes que cambian los iconos de la interfaz de usuario.

Agregar la dependencia:

Para agregar la dependencia al archivo pubspec.yaml se puede seguir la siguiente imagen:

dependency

Importación de la dependencia:

Para importar la dependencia flutter_rating_bar al archivo main.dart, usa lo siguiente:

import 'package:flutter_rating_bar/flutter_rating_bar.dart';

Estructuración de la aplicación: 

Se puede usar un StatefulWidget para darle a la aplicación una barra de aplicaciones y un cuerpo para almacenar contenido, como se muestra a continuación:

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

Diseño de una barra de calificación vertical:

Se puede invocar una barra de calificación simple desde el paquete flutter_rating_bar llamando al widget RatingBar como se muestra a continuación:

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

Agregar un interruptor RTL:

En esta etapa, agregaremos un interruptor que puede cambiar la alineación de la barra de clasificación de izquierda a derecha y de derecha a izquierda. Se puede hacer usando MainAxisAlignment como MainAxisAlignment.center y llamando al modo _isRTL como se muestra a continuación:

Dart

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

Agregar un interruptor de alineación vertical:

En esta etapa, agregaremos un interruptor que puede cambiar la alineación de la barra de clasificación de izquierda a derecha y de derecha a izquierda. Se puede hacer usando MainAxisAlignment como MainAxisAlignment.center y llamando al modo _isVertical como se muestra a continuación:

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

Adición de modos a la barra de calificación:

En esta aplicación, agregaremos 3 modos y, al seleccionar cada modo, cambiará el ícono de la barra de clasificación. Usaremos la función switch() para asignar los casos a los modos y asignarles íconos como se muestra a continuación:

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

Código fuente completo:

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

Producción:

Publicación traducida automáticamente

Artículo escrito por ddeevviissaavviittaa y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *