我正在尝试创建一个用于用户评分的星形栏,下面的图片来自play商店,以说明我正在尝试实现的目标:
我已经实现了以下功能,正如你所看到的,这是功能性的,但当我查看我的代码时,我觉得肯定有一种更聪明的方法来做到这一点,真正令人困扰的是,IconButton
的命中区域被向上移动了一点,所以当你触摸实际的星星时,它不会注册为触摸事件(即:你必须瞄准比按钮所在位置更高的位置,才能注册你的触摸,这会造成糟糕的UX)你可以通过关注我点击任何星星时的闪屏效果来检查我的意思:
var _myColorOne = Colors.grey;
var _myColorTwo = Colors.grey;
var _myColorThree = Colors.grey;
var _myColorFour = Colors.grey;
var _myColorFive = Colors.grey;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("My Rating"),
),
body: new Center(
child: new Container(
height: 10.0,
width: 500.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new IconButton(icon: new Icon(Icons.star),
onPressed: ()=>setState((){
_myColorOne=Colors.orange;
_myColorTwo=null;
_myColorThree=null;
_myColorFour=null;
_myColorFive=null;
}),color: _myColorOne,),
new IconButton(icon: new Icon(Icons.star),
onPressed: ()=>setState((){
_myColorOne=Colors.orange;
_myColorTwo=Colors.orange;
_myColorThree=Colors.grey;
_myColorFour=Colors.grey;
_myColorFive=Colors.grey;
}),color: _myColorTwo,),
new IconButton(icon: new Icon(Icons.star), onPressed: ()=>setState((){
_myColorOne=Colors.orange;
_myColorTwo=Colors.orange;
_myColorThree=Colors.orange;
_myColorFour=Colors.grey;
_myColorFive=Colors.grey;
}),color: _myColorThree,),
new IconButton(icon: new Icon(Icons.star), onPressed: ()=>setState((){
_myColorOne=Colors.orange;
_myColorTwo=Colors.orange;
_myColorThree=Colors.orange;
_myColorFour=Colors.orange;
_myColorFive=Colors.grey;
}),color: _myColorFour,),
new IconButton(icon: new Icon(Icons.star), onPressed: ()=>setState((){
_myColorOne=Colors.orange;
_myColorTwo=Colors.orange;
_myColorThree=Colors.orange;
_myColorFour=Colors.orange;
_myColorFive=Colors.orange;
}),color: _myColorFive,),
],
),
),
),
);
}
那么这里更好的方法是什么呢?
发布于 2017-10-09 19:49:33
太多的重复和填充!废话
不管怎样,这就是我要做的。简单,可重用。你可以在不点击和不点击的情况下使用(不点击,禁用涟漪效果)。半星也是。如果未指定颜色,则对填充的星形使用原色。
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),
);
}
}
发布于 2017-10-09 16:40:50
发生这种情况的原因是为行小部件指定的高度。手势仅被检测到该高度。删除高度将缩放行以适合子项,从而允许完美地检测IconButton上的点击手势。
我想我做了一个稍微好一点的解决方案。
评分组件代码:
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),
)
],
),
),
),
);
}
如果您希望使用问题中的代码,请替换:
child: new Container(
height: 10.0,
width: 500.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
通过以下方式:
child: new Container(
width: 500.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
希望这能有所帮助!
发布于 2019-03-11 19:11:55
如果任何人也想显示文本,那么您可以使用这段代码。这段代码既可以处理双精度值,也可以处理整型值,我在这里的smoothStarRating中使用了SmoothStarRating小部件。这是相当好的:)如果发现有用,请对此答案给予支持。
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',
),
https://stackoverflow.com/questions/46637566
复制相似问题