Dart 如何正确创建评级星形条?
我正在尝试为用户评级创建一个星形条,下图来自play store,以说明我正在尝试实现的目标: 我已经能够实现以下功能,正如您所看到的,但是当我查看我的代码时,我觉得必须有一种更聪明的方法来实现它,而真正的问题是,Dart 如何正确创建评级星形条?,dart,flutter,Dart,Flutter,我正在尝试为用户评级创建一个星形条,下图来自play store,以说明我正在尝试实现的目标: 我已经能够实现以下功能,正如您所看到的,但是当我查看我的代码时,我觉得必须有一种更聪明的方法来实现它,而真正的问题是,IconButton命中区域被上移了一点,所以当您触摸实际的星星时,它不会注册为触摸事件(即:你必须瞄准高于按钮位置的位置,才能注册你的触摸,这会造成糟糕的用户体验)当我点击任何星星时,你可以通过观察飞溅效果来检查我的意思: var\u myColorOne=Colors.grey
IconButton
命中区域被上移了一点,所以当您触摸实际的星星时,它不会注册为触摸事件(即:你必须瞄准高于按钮位置的位置,才能注册你的触摸,这会造成糟糕的用户体验)当我点击任何星星时,你可以通过观察飞溅效果来检查我的意思:
var\u myColorOne=Colors.grey;
var _myColorTwo=颜色。灰色;
var_myColorThree=颜色。灰色;
var_myColorFour=颜色。灰色;
var_myColorFive=颜色。灰色;
@凌驾
小部件构建(构建上下文){
归还新脚手架(
appBar:新的appBar(
标题:新文本(“我的评级”),
),
正文:新中心(
子容器:新容器(
身高:10.0,
宽度:500.0,
孩子:新的一排(
mainAxisAlignment:mainAxisAlignment.center,
儿童:[
新图标按钮(图标:新图标(Icons.star),
按下时:()=>设置状态(){
_myColorOne=Colors.orange;
_myColorTwo=null;
_myColorThree=null;
_myColorFour=null;
_mycolor5=null;
}),颜色:_myColorOne,),
新图标按钮(图标:新图标(Icons.star),
按下时:()=>设置状态(){
_myColorOne=Colors.orange;
_myColorTwo=颜色。橙色;
_myColorThree=颜色。灰色;
_myColorFour=颜色。灰色;
_myColorFive=颜色。灰色;
}),颜色:_myColorTwo,),
新图标按钮(图标:新图标(Icons.star),ON按下:()=>setState(){
_myColorOne=Colors.orange;
_myColorTwo=颜色。橙色;
_myColorThree=颜色。橙色;
_myColorFour=颜色。灰色;
_myColorFive=颜色。灰色;
}),颜色:_mycolor三,),
新图标按钮(图标:新图标(Icons.star),ON按下:()=>setState(){
_myColorOne=Colors.orange;
_myColorTwo=颜色。橙色;
_myColorThree=颜色。橙色;
_myColorFour=颜色。橙色;
_myColorFive=颜色。灰色;
}),颜色:_myColorFour,),
新图标按钮(图标:新图标(Icons.star),ON按下:()=>setState(){
_myColorOne=Colors.orange;
_myColorTwo=颜色。橙色;
_myColorThree=颜色。橙色;
_myColorFour=颜色。橙色;
_myColorFive=颜色。橙色;
}),颜色:_mycolor5,),
],
),
),
),
);
}
因此,这里更好的方法是什么?这是因为为行小部件指定了高度。手势仅检测到该高度。移除该高度将缩放行以适合儿童,从而允许完美检测图标按钮上的点击手势 我想我提出了一个稍微好一点的解决方案 评级组件代码:
int _rating = 0;
void rate(int rating) {
//Other actions based on rating such as api calls.
setState(() {
_rating = rating;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("My Rating"),
),
body: new Center(
child: new Container(
width: 500.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new GestureDetector(
child: new Icon(
Icons.star,
color: _rating >= 1 ? Colors.orange : Colors.grey,
),
onTap: () => rate(1),
),
new GestureDetector(
child: new Icon(
Icons.star,
color: _rating >= 2 ? Colors.orange : Colors.grey,
),
onTap: () => rate(2),
),
new GestureDetector(
child: new Icon(
Icons.star,
color: _rating >= 3 ? Colors.orange : Colors.grey,
),
onTap: () => rate(3),
),
new GestureDetector(
child: new Icon(
Icons.star,
color: _rating >= 4 ? Colors.orange : Colors.grey,
),
onTap: () => rate(4),
),
new GestureDetector(
child: new Icon(
Icons.star,
color: _rating >= 5 ? Colors.orange : Colors.grey,
),
onTap: () => rate(5),
)
],
),
),
),
);
}
与:
希望这有帮助!重复和填充太多了!呸 不管怎样,我就是这么做的。简单,可重复使用。 您可以在单击和不单击的情况下使用它(不单击将禁用涟漪效应)。 半星形。如果没有指定颜色,则使用填充星形的原色
typedef void RatingChangeCallback(双重评级);
类星号扩展了无状态小部件{
最终整数星数;
最终双重评级;
最终额定值更改回调额定值更改;
最终颜色;
星号({this.starCount=5,this.rating=0,this.onRatingChanged,this.color});
小部件buildStar(BuildContext上下文,int索引){
图标;
如果(指数>=评级){
图标=新图标(
Icons.star_边框,
颜色:主题。背景。按钮颜色,
);
}
否则如果(指数>评级-1&&指数<评级){
图标=新图标(
图标。星半,
颜色:颜色??主题(上下文)。原色,
);
}否则{
图标=新图标(
明星,
颜色:颜色??主题(上下文)。原色,
);
}
返回新的InkResponse(
onTap:onRatingChanged==null?null:()=>onRatingChanged(索引+1.0),
孩子:图标,
);
}
@凌驾
小部件构建(构建上下文){
返回新行(子项:newlist.generate(starCount,(index)=>buildStar(context,index));
}
}
然后您可以这样使用它:
class Test extends StatefulWidget {
@override
_TestState createState() => new _TestState();
}
class _TestState extends State<Test> {
double rating = 3.5;
@override
Widget build(BuildContext context) {
return new StarRating(
rating: rating,
onRatingChanged: (rating) => setState(() => this.rating = rating),
);
}
}
类测试扩展StatefulWidget{
@凌驾
_TestState createState()=>new_TestState();
}
类_TestState扩展状态{
双重评级=3.5;
@凌驾
小部件构建(构建上下文){
回归新星光(
评级:评级,
onRatingChanged:(评级)=>setState(()=>this.rating=评级),
);
}
}
这是我的
List<bool> ratingStarStatus = <bool>[
true,
false,
false,
false,
false
];
int rating=1;
Widget addImage(String icon){
return new Image.asset(
icon,
height: 25.0,
width: 25.0,
);
}
Widget addRatingImage(int index){
return new InkWell(
onTap: (){
rating=index+1;
reDrawRating(index);
},
child: addImage(ratingStarStatus[index]?Constant.iconStarEnable: Constant.iconStarDisable)
);
}
void reDrawRating(int index){
for(int i=0;i<5;i++){
if(i<=index){
setState(() {
ratingStarStatus[i]=true;
});
}else{
setState(() {
ratingStarStatus[i]=false;
});
}
}
}
Widget addRatingView(){
var stars = <Widget>[];
for (var i = 0; i < 5; i++) {
var star = addRatingImage(i);
var padding = new Padding(padding: const EdgeInsets.fromLTRB(0.0, 0.0, 12.0, 0.0));
stars.add(star);
stars.add(padding);
}
return new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: stars,
);
}
List ratingStarStatus=[
是的,
假,,
假,,
假,,
假的
];
内部评级=1;
小部件添加图像(字符串图标){
返回新的Image.asset(
偶像
身高:25.0,
宽度:25.0,
);
}
小部件添加图像(整数索引){
返回新墨水池(
onTap:(){
评级=指数+1;
重画评级(指数);
},
子项:addImage(评级开始状态[索引]?常量。IConstable:常量。IConstardinable)
);
}
无效重绘(整数索引){
对于(inti=0;i如果有人想显示文本,那么您可以使用这段代码。
该代码既可以用于double,也可以用于in
child: new Container(
width: 500.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
typedef void RatingChangeCallback(double rating);
class StarRating extends StatelessWidget {
final int starCount;
final double rating;
final RatingChangeCallback onRatingChanged;
final Color color;
StarRating({this.starCount = 5, this.rating = .0, this.onRatingChanged, this.color});
Widget buildStar(BuildContext context, int index) {
Icon icon;
if (index >= rating) {
icon = new Icon(
Icons.star_border,
color: Theme.of(context).buttonColor,
);
}
else if (index > rating - 1 && index < rating) {
icon = new Icon(
Icons.star_half,
color: color ?? Theme.of(context).primaryColor,
);
} else {
icon = new Icon(
Icons.star,
color: color ?? Theme.of(context).primaryColor,
);
}
return new InkResponse(
onTap: onRatingChanged == null ? null : () => onRatingChanged(index + 1.0),
child: icon,
);
}
@override
Widget build(BuildContext context) {
return new Row(children: new List.generate(starCount, (index) => buildStar(context, index)));
}
}
class Test extends StatefulWidget {
@override
_TestState createState() => new _TestState();
}
class _TestState extends State<Test> {
double rating = 3.5;
@override
Widget build(BuildContext context) {
return new StarRating(
rating: rating,
onRatingChanged: (rating) => setState(() => this.rating = rating),
);
}
}
List<bool> ratingStarStatus = <bool>[
true,
false,
false,
false,
false
];
int rating=1;
Widget addImage(String icon){
return new Image.asset(
icon,
height: 25.0,
width: 25.0,
);
}
Widget addRatingImage(int index){
return new InkWell(
onTap: (){
rating=index+1;
reDrawRating(index);
},
child: addImage(ratingStarStatus[index]?Constant.iconStarEnable: Constant.iconStarDisable)
);
}
void reDrawRating(int index){
for(int i=0;i<5;i++){
if(i<=index){
setState(() {
ratingStarStatus[i]=true;
});
}else{
setState(() {
ratingStarStatus[i]=false;
});
}
}
}
Widget addRatingView(){
var stars = <Widget>[];
for (var i = 0; i < 5; i++) {
var star = addRatingImage(i);
var padding = new Padding(padding: const EdgeInsets.fromLTRB(0.0, 0.0, 12.0, 0.0));
stars.add(star);
stars.add(padding);
}
return new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: stars,
);
}
Text(
rate == 5.0
? 'Its 5'
: ((rate < 5.0) & (rate > 3.0))
? 'Its 4'
: ((rate < 4.0) & (rate > 2.0))
? 'Its 3'
: ((rate < 3.0) & (rate > 1.0))
? 'Its 2'
: ((rate < 2.0) & (rate > 0.0))
? 'Its 1'
: 'Its0',
),
`class RatingsWidget extends StatefulWidget {
@override
_RatingsWidgetState createState() => _RatingsWidgetState();
}
class _RatingsWidgetState extends State<RatingsWidget> {
int _rating = 0;
@override
Widget build(BuildContext context) {
List<Widget> array = [];
var filled = Colors.blue;
var empty = Colors.black;
for (var i = 1; i <= 5; i++) {
array.add(IconButton(
icon: Icon(Icons.star),
color: (_rating < i ? empty : filled),
onPressed: () {
setState(() {
_rating = i;
});
},
));
}
return Row(
children: array,
mainAxisAlignment: MainAxisAlignment.center,
);
}
}`
import 'package:flutter/material.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var rating = 0.0;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Rating bar demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: SmoothStarRating(
rating: rating,
size: 45,
starCount: 5,
onRatingChanged: (value) {
setState(() {
rating = value;
});
},
)),
),
);
}
}
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);
},
);
class RatingButtons extends StatefulWidget {
const RatingButtons({
Key key,
@required this.feedbackIcons,
}) : super(key: key);
final List<Widget> feedbackIcons;
//Here you can create a list of icons for rating or
//you can pass the icon list while using this widget
@override
_RatingButtonsState createState() => _RatingButtonsState();
}
class _RatingButtonsState extends State<RatingButtons> {
int rating;
@override
Widget build(BuildContext context) {
return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
...widget.feedbackIcons.map((icon) {
return GestureDetector(
child: rating == widget.feedbackIcons.indexOf(icon)
? CircleAvatar(
radius: 30,
backgroundColor: kThemeColor,
child: icon,
)
: icon,
onTap: () {
setState(() {
rating = widget.feedbackIcons.indexOf(icon);
});
},
);
}).toList()
]);
}
}