如何正确创建评分星形条?

问题描述:

我试图创建的用户评级的明星吧,下图是从Play商店来说明什么,我想实现:如何正确创建评分星形条?

enter image description here

我已经能够实现以下,这是功能正如你所看到的,但是当我看着我的代码,我觉得必须有一个更聪明的方式来做到这一点,真正的问题在于IconButton命中区域正在向上移动一点点,所以当你触摸它没有注册为触摸事件的实际明星(即:你必须瞄准的位置高于按钮定位的位置,以便你的触摸被注册,这会导致用户体验不佳),您可以通过保留注视飞溅效果T当我点击的星星:

enter image description here

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,), 
       ], 

     ), 
     ), 
    ), 
    ); 
    } 

那么,什么是更好的方法吗?

太多的重复和填充!嗯

无论如何,这就是我该怎么做。简单,可重复使用。 无论是否点击都可以使用它(不点击禁用连锁效果)。 也是半星。如果没有指定颜色,则使用原色填充星星。

enter image description here

“黑” 星彩是在这张照片不正确。它在手机上是灰色的,但由于颤动问题,它在我的模拟器中显示为黑色。

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))); 
    } 
} 

然后,您可以使用它像这样:

​​
+0

我不知道我应该设置'onRatingChanged:',为了通过点击启用评级? – aziza

+0

大多数时候,一个''(rating)=> setState(()=> this。评分=评分))'应该够了 – Darky

+0

你能澄清一下吗?不是'onRatingChanged'应该设置为类似于'onRatingChanged:(RatingChangeCallback)=> ....' – aziza

发生这种情况的原因是为行窗口小部件指定了高度。手势只能检测到该高度。删除高度将缩放该行以适合儿童,从而允许完美地检测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, 

希望这有助于!

+0

与> =检查的颜色干得漂亮;) –

+0

如何内联率()方法中的onTap:()=>的setState (()=> _rating = 1)? –

+0

如果没有基于评级触发的动作,内联率方法是一个好主意。我认为内联评级可能会导致5次修改,以便根据评级触发任何行动。在费率方法中添加了评论,希望这是有道理的。 –