我正在尝试为用户评分创建一个星条,下图来自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,), ], ), ), ), ); }
那么,这里有什么更好的方法呢?
太多重复和填充!h
无论如何,这就是我要做的。简单,可重用。您可以在没有点击的情况下使用它(没有点击会禁用波纹效果)。也是半颗星。如果未指定颜色,则对填充的星星使用原色。
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))); } }
You can then use it like this :
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), ); } }