Skip to content

Commit 4c61094

Browse files
authored
Merge pull request #81 from deepikahr/rating
Rating
2 parents 9e034f6 + 011fb04 commit 4c61094

6 files changed

Lines changed: 214 additions & 71 deletions

File tree

example/lib/assets/heart.png

8.16 KB
Loading
14 KB
Loading

example/lib/assets/heart_half.png

11.4 KB
Loading

example/lib/main.dart

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ class _MyHomePageState extends State<MyHomePage>
4040
GlobalKey<ScaffoldState>();
4141

4242
TabController tabController;
43+
final _ratingController = TextEditingController();
44+
double _rating = 3.5;
45+
double _userRating = 4.5;
4346

4447
@override
4548
void initState() {
4649
super.initState();
50+
_ratingController.text = '4.5';
4751
tabController = TabController(length: 3, vsync: this);
4852
}
4953

@@ -67,8 +71,6 @@ class _MyHomePageState extends State<MyHomePage>
6771
'Xamarin2',
6872
];
6973

70-
double rating = 3.5;
71-
7274
@override
7375
Widget build(BuildContext context) => Scaffold(
7476
drawer: GFDrawer(
@@ -214,50 +216,106 @@ class _MyHomePageState extends State<MyHomePage>
214216
}),
215217

216218
GFRating(
217-
rating: rating,
218-
// itemSize: 65,
219-
filledIcon: Icons.star,
220-
halfFilledIcon: Icons.star_half,
221-
defaultIcon: Icons.star_border,
222-
itemCount: 5,
223-
allowHalfRating: false,
224-
spacing: 2,
219+
rating: _rating,
220+
itemSize: 50,
221+
// filledIcon: Image.asset(
222+
// 'lib/assets/heart.png',
223+
// height: 50,
224+
// width: 50,
225+
// color: Colors.amber,
226+
// ),
227+
// halfFilledIcon: Image.asset(
228+
// 'lib/assets/heart_half.png',
229+
// height: 50,
230+
// width: 50,
231+
// color: Colors.amber,
232+
// ),
233+
// defaultIcon: Image.asset(
234+
// 'lib/assets/heart_border.png',
235+
// height: 50,
236+
// width: 50,
237+
// color: Colors.amber,
238+
// ),
239+
// allowHalfRating: false,
240+
spacing: 8,
225241
color: Colors.teal,
226242
borderColor: Colors.tealAccent,
227243
onRatingChanged: (value) {
228244
setState(() {
229-
rating = value;
245+
_rating = value;
246+
print('user selected $_rating');
230247
});
231248
},
232249
),
233250

234-
GFCard(
235-
content: Column(
236-
children: <Widget>[
237-
const GFTypography(
238-
text: 'Toast',
239-
type: GFTypographyType.typo6,
240-
),
241-
const SizedBox(
242-
height: 20,
243-
),
244-
const SizedBox(
245-
height: 20,
246-
),
247-
GFToast(
248-
text: 'Happy New Year',
249-
button: GFButton(
250-
onPressed: () {
251-
print('dfr');
252-
},
253-
text: 'OK',
254-
type: GFButtonType.outline,
255-
color: GFColor.warning,
256-
),
257-
),
258-
],
251+
SizedBox(
252+
height: 20,
253+
child: Text('selected rating ${_rating.toStringAsFixed(1)}'),
254+
),
255+
256+
GFRating(
257+
rating: _userRating,
258+
itemSize: 50,
259+
filledIcon: Image.asset(
260+
'lib/assets/heart.png',
261+
height: 50,
262+
width: 50,
263+
color: Colors.amber,
264+
),
265+
halfFilledIcon: Image.asset(
266+
'lib/assets/heart_half.png',
267+
height: 50,
268+
width: 50,
269+
color: Colors.amber,
270+
),
271+
defaultIcon: Image.asset(
272+
'lib/assets/heart_border.png',
273+
height: 50,
274+
width: 50,
275+
color: Colors.amber,
276+
),
277+
ratingController: _ratingController,
278+
textFormRating: true,
279+
spacing: 8,
280+
color: Colors.teal,
281+
borderColor: Colors.tealAccent,
282+
suffixIcon: MaterialButton(
283+
onPressed: () {
284+
setState(() {
285+
_userRating = double.parse(_ratingController.text ?? '0.0');
286+
});
287+
},
288+
child: const Text('Rate'),
259289
),
260290
),
291+
292+
// GFCard(
293+
// content: Column(
294+
// children: <Widget>[
295+
// const GFTypography(
296+
// text: 'Toast',
297+
// type: GFTypographyType.typo6,
298+
// ),
299+
// const SizedBox(
300+
// height: 20,
301+
// ),
302+
// const SizedBox(
303+
// height: 20,
304+
// ),
305+
// GFToast(
306+
// text: 'Happy New Year',
307+
// button: GFButton(
308+
// onPressed: () {
309+
// print('dfr');
310+
// },
311+
// text: 'OK',
312+
// type: GFButtonType.outline,
313+
// color: GFColor.warning,
314+
// ),
315+
// ),
316+
// ],
317+
// ),
318+
// ),
261319
//
262320
// GFCard(
263321
// content: Column(

example/pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ flutter:
2828
assets:
2929
- lib/assets/food.jpeg
3030
- lib/assets/img.png
31+
- lib/assets/heart.png
32+
- lib/assets/heart_border.png
33+
- lib/assets/heart_half.png

lib/components/rating/gf_rating.dart

Lines changed: 117 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
22

33
typedef 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

Comments
 (0)