@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
22
33typedef RatingChangeCallback = void Function (double rating);
44
5- class GFRating extends StatelessWidget {
5+ class GFRating extends StatefulWidget {
66 const GFRating ({
77 this .itemCount = 5 ,
88 this .spacing = 0.0 ,
@@ -15,6 +15,12 @@ class GFRating extends StatelessWidget {
1515 this .filledIcon,
1616 this .halfFilledIcon,
1717 this .allowHalfRating = true ,
18+ this .textFormRating = false ,
19+ this .suffixIcon,
20+ this .ratingController,
21+ this .inputDecorations,
22+ this .margin = const EdgeInsets .symmetric (vertical: 16 ),
23+ this .padding = const EdgeInsets .symmetric (horizontal: 16 ),
1824 }) : assert (rating != null );
1925
2026 /// defines total number of rating items
@@ -33,13 +39,13 @@ class GFRating extends StatelessWidget {
3339 final bool allowHalfRating;
3440
3541 /// defines the items when filled
36- final IconData filledIcon;
42+ final Widget filledIcon;
3743
3844 /// defines the items when half-filled
39- final IconData halfFilledIcon;
45+ final Widget halfFilledIcon;
4046
4147 /// defines the default items, when having filledIcon && halfFilledIcon
42- final IconData defaultIcon;
48+ final Widget defaultIcon;
4349
4450 /// defines the space between items
4551 final double spacing;
@@ -50,49 +56,125 @@ class GFRating extends StatelessWidget {
5056 /// return current rating whenever rating is updated
5157 final RatingChangeCallback onRatingChanged;
5258
59+ /// if true, shows rating [TextFormField] with the rating bar, that allows the user input to show rating
60+ final bool textFormRating;
61+
62+ /// defines the design and funtion of rating [TextFormField] 's suffix icon
63+ final Widget suffixIcon;
64+
65+ /// controls the [TextField] Controller of rating [TextFormField]
66+ final TextEditingController ratingController;
67+
68+ /// defines the [InputDecoration] of rating [TextFormField]
69+ final InputDecoration inputDecorations;
70+
71+ /// defines the margin of rating [TextFormField]
72+ final EdgeInsets margin;
73+
74+ /// defines the padding of rating [TextFormField]
75+ final EdgeInsets padding;
76+
77+ @override
78+ _GFRatingState createState () => _GFRatingState ();
79+ }
80+
81+ class _GFRatingState extends State <GFRating > {
5382 Widget buildRatingBar (BuildContext context, int index) {
54- Icon icon;
55- if (index >= rating) {
56- icon = Icon (
57- defaultIcon != null ? defaultIcon : Icons .star_border,
58- color: borderColor ?? Theme .of (context).primaryColor,
59- size: itemSize,
60- );
61- } else if (index > rating - (allowHalfRating ? 0.5 : 1.0 ) &&
62- index <= rating) {
63- icon = Icon (
64- halfFilledIcon != null ? halfFilledIcon : Icons .star_half,
65- color: color ?? Theme .of (context).primaryColor,
66- size: itemSize,
67- );
83+ Widget icon;
84+ if (index >= widget.rating) {
85+ icon = widget.defaultIcon != null
86+ ? widget.defaultIcon
87+ : Icon (
88+ Icons .star_border,
89+ color: widget.borderColor ?? Theme .of (context).primaryColor,
90+ size: widget.itemSize,
91+ );
92+ } else if (! widget.textFormRating
93+ ? index > widget.rating - (widget.allowHalfRating ? 0.5 : 1.0 ) &&
94+ index < widget.rating
95+ : index + 1 == widget.rating + 0.5 ) {
96+ icon = widget.halfFilledIcon != null
97+ ? widget.halfFilledIcon
98+ : Icon (
99+ Icons .star_half,
100+ color: widget.color ?? Theme .of (context).primaryColor,
101+ size: widget.itemSize,
102+ );
68103 } else {
69- icon = Icon (
70- filledIcon != null ? filledIcon : Icons .star,
71- color: color ?? Theme .of (context).primaryColor,
72- size: itemSize,
73- );
104+ icon = widget.filledIcon != null
105+ ? widget.filledIcon
106+ : Icon (
107+ Icons .star,
108+ color: widget.color ?? Theme .of (context).primaryColor,
109+ size: widget.itemSize,
110+ );
74111 }
75112
76113 return GestureDetector (
77114 onTap: () {
78- if (onRatingChanged != null ) {
79- onRatingChanged (index + 1.0 );
115+ if (widget.onRatingChanged != null ) {
116+ widget.onRatingChanged (index + 1.0 );
117+ }
118+ },
119+ onHorizontalDragUpdate: (dragDetails) {
120+ final RenderBox box = context.findRenderObject ();
121+ final _pos = box.globalToLocal (dragDetails.globalPosition);
122+ final i = _pos.dx / widget.itemSize;
123+ var newRating = widget.allowHalfRating ? i : i.round ().toDouble ();
124+ if (newRating > widget.itemCount) {
125+ newRating = widget.itemCount.toDouble ();
126+ }
127+ if (newRating < 0 ) {
128+ newRating = 0.0 ;
129+ }
130+ if (widget.onRatingChanged != null ) {
131+ widget.onRatingChanged (newRating);
80132 }
81133 },
82134 child: icon,
83135 );
84136 }
85137
86138 @override
87- Widget build (BuildContext context) => Material (
88- color: Colors .transparent,
89- child: Wrap (
90- alignment: WrapAlignment .center,
91- spacing: spacing,
92- children: List .generate (
93- itemCount,
94- (index) => buildRatingBar (context, index),
139+ Widget build (BuildContext context) => widget.textFormRating
140+ ? Column (children: < Widget > [
141+ Container (
142+ margin: widget.margin,
143+ padding: widget.padding,
144+ child: TextFormField (
145+ controller: widget.ratingController,
146+ keyboardType: TextInputType .number,
147+ decoration: widget.inputDecorations == null
148+ ? InputDecoration (
149+ border: const OutlineInputBorder (),
150+ hintText: 'Enter rating' ,
151+ labelText: 'Enter rating' ,
152+ suffixIcon: widget.suffixIcon,
153+ )
154+ : widget.inputDecorations,
155+ ),
156+ ),
157+ Material (
158+ color: Colors .transparent,
159+ child: Wrap (
160+ alignment: WrapAlignment .center,
161+ spacing: widget.spacing,
162+ children: List .generate (
163+ widget.itemCount,
164+ (index) => buildRatingBar (context, index),
165+ ),
166+ ),
167+ )
168+ ])
169+ : Material (
170+ color: Colors .transparent,
171+ child: Wrap (
172+ alignment: WrapAlignment .center,
173+ spacing: widget.spacing,
174+ children: List .generate (
175+ widget.itemCount,
176+ (index) => buildRatingBar (context, index),
177+ ),
95178 ),
96- ),
97- );
179+ );
98180}
0 commit comments