Flutter星级评选

949 阅读1分钟

1.效果图

2.设计思路

  • 确定使用Stack叠加效果主件,下面采用空(☆),上面叠加实心的(★).
  • 对外提供以下属性让外界设置:
                       
                        1.选中的颜色
                        2.未选中的颜色
                        3.星星总个数
                        4.平分最大值
                        5.当前平分值
                        6.星星的图片

3.代码实现

1.创建MaterialApp

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme:
          ThemeData(primaryColor: Colors.blue, splashColor: Colors.transparent),
      home: Scaffold(
        appBar: AppBar(
          title: Text("StarDemo"),
        ),
        body: Center(
          child: StarRating(
            rating: 6.8,
            count: 5,
          ),
        ),
      ),
    );
  }
}

2.创建Stack控件

class StarRating extends StatefulWidget {
  /*外界控制的参数*/
  final int count;
  final double rating;
  final double maxRating;
  final double size;
  final Color unselectedColor;
  final Color selectedColor;
  final Widget selectedImage;
  final Widget unselectedImage;

  /*必传参数和默认值*/
  StarRating(
      {@required this.rating,
      this.count = 5,
      this.maxRating = 10,
      this.size = 30,
      this.unselectedColor = const Color(0xffbbbbbb),
      this.selectedColor = const Color(0xffff0000),
      Widget unselectedImage,
      Widget selectedImage})
      : unselectedImage = unselectedImage ??
            Icon(Icons.star_border, color: unselectedColor, size: size),
        selectedImage =
            selectedImage ?? Icon(Icons.star, color: selectedColor, size: size);

  @override
  _StarRatingState createState() => _StarRatingState();
}

class _StarRatingState extends State {
  @override
  Widget build(BuildContext context) {
    /*stack主件叠加实现*/
    return Stack(
      children: [
        /*选中的🌟和未选中的🌟*/
        Row(mainAxisSize: MainAxisSize.min, children: buildUnselectedStar()),
        Row(mainAxisSize: MainAxisSize.min, children: buildSelectedStar()),
      ],
    );
  }

3.未选中的星星

/*未选中🌟*/
  List buildUnselectedStar() {
    return List.generate(widget.count, (index) {
      return widget.unselectedImage;
    });
  }

4.选中的星星

/*选中的🌟*/
  List buildSelectedStar() {
    //1.创建star
    List stars = [];
    final star = widget.selectedImage;

    //构建填充满的star
    double oneValue = widget.maxRating / widget.count; //每一个占用几分
    int entireCount = (widget.rating / oneValue).floor(); //不满一个向下取整

    for (var i = 0; i < entireCount; i++) {
      stars.add(star);
    }

    /*构建部分填充star*/
    //个数减去整数个乘以一个宽带(3.5-3)*30
    double leftwidth = ((widget.rating / oneValue) - entireCount) * widget.size;
    final partStar = ClipRect(
      child: star,
      clipper: StarClipper(leftwidth),
    );

    stars.add(partStar);

    //如果平分大于上限就裁剪
    if (stars.length > widget.count) {
      return stars.sublist(0, widget.count);
    }
    return stars;
  }
}

5.裁剪不满一个星星

/*自己裁剪🌟*/
class StarClipper extends CustomClipper {
  double width;

  StarClipper(this.width);

  @override
  Rect getClip(Size size) {
    return Rect.fromLTRB(0, 0, width, size.height);
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}