flutter StarRating



StarRating

[Flutter-27] StarRating 星星评级_i++

1. 产品使用原型如上gif

1. 创建一个star_rating.dart 文件

import 'package:flutter/material.dart';

/* Class: LStarRating 等级评分
*/
class LStarRating extends StatefulWidget {
final double rating; // 当前评分、必传参数
final double maxRating; // 最高评分、默认为10
final Widget unselectedImage; // 未选中的星星图片
final Widget selectedImage; // 选中的星星的图片
final int count; // 星星个数
final double size; // 星星大小
final Color unselectedColor; // 星星未选中颜色
final Color selectedColor; // 星星选中颜色
final bool isShowLeftText; // 左边是否显示标题
final Widget leftTextWidget; // 自定义定制左边文字Widget
final String leftText; // 左边文字
final double leftTextRightMargin; // 左边标题跟星星的间距

LStarRating({
required this.rating, //
this.maxRating = 5,
this.size = 25,
this.unselectedColor = const Color(0xffbbbbbb),
this.selectedColor = const Color(0xffe0aa46),
Widget?
unselectedImage, //
Widget? selectedImage,
Widget? leftTextWidget,
this.count = 5,
this.isShowLeftText = false,
this.leftTextRightMargin = 10,
this.leftText = '物流服务',
}) : assert(rating <= maxRating),
unselectedImage = unselectedImage ??
Icon(Icons.star, size: size, color: unselectedColor),
selectedImage =
selectedImage ?? Icon(Icons.star, size: size, color: selectedColor),
leftTextWidget =
leftTextWidget ?? Text(leftText, style: TextStyle(fontSize: 16));

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

class _LStarRatingState extends State<LStarRating> {
@override
Widget build(BuildContext context) {
return Center(
child: Row(
mainAxisSize: MainAxisSize.min, // 如果不设置就会不居中...
children: [
widget.isShowLeftText ? widget.leftTextWidget : Container(),
widget.isShowLeftText
? SizedBox(width: widget.leftTextRightMargin)
: SizedBox(width: 0),
oneLineStarRating(),
],
),
);
}

/* 一行只有星星评级【为选中星星 + 选中星星】
*/
Widget oneLineStarRating() {
return Stack(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: getUnselectedStarRatingImage(),
),
Row(
mainAxisSize: MainAxisSize.min,
children: getSelectedStarRatingImage(),
),
],
);
}

// 获取未选中的星级评定
List<Widget> getUnselectedStarRatingImage() {
return List.generate(widget.count, (index) => widget.unselectedImage);
}

// 获取选中的星级评定
List<Widget> getSelectedStarRatingImage() {
// 计算每一个星星分
double oneStarRatingValue = widget.maxRating / widget.count;

// 计算用户评价的分数显示几颗星, 取整数高亮
int entireCount = (widget.rating / oneStarRatingValue).floor();

// 计算剩下未选中星星分
double leftStarRatingValue =
widget.rating - entireCount * oneStarRatingValue;

// 计算剩余未选中星星分数的比率
double leftStarRatingRatio = leftStarRatingValue / oneStarRatingValue;

// 获取评分Star前面整数部分
List<Widget> selectedImages = [];
for (int i = 0; i < entireCount; i++) {
selectedImages.add(widget.selectedImage);
}

// 3.计算: 如果leftStarValue==0.0, 还是会创建一个星星、造成不居中对齐
if (leftStarRatingRatio != 0.0) {
Widget leftStar = ClipRect(
clipper: MyRectClipper(width: leftStarRatingRatio * widget.size),
child: widget.selectedImage,
);
selectedImages.add(leftStar);
}

return selectedImages;
}
}

/* ClipRect + CustomClipper
可以使用ClipRect定制CustomClipper进行裁剪
定义CustomClipper裁剪规则:
*/
class MyRectClipper extends CustomClipper<Rect> {
final double width;

MyRectClipper({this.width = 0.0});

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

@override
bool shouldReclip(MyRectClipper oldClipper) {
return width != oldClipper.width;
}
}


2. 如何具体使用?

class Content extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.center,
children: [
LStarRating(rating: 5.0, isShowLeftText: true),
LStarRating(rating: 3.9, isShowLeftText: true, leftText: '商家服务'),
LStarRating(rating: 2.5, isShowLeftText: true, leftText: '客服服务'),
LStarRating(rating: 2.4, isShowLeftText: true, leftText: '产品质量'),
LStarRating(rating: 3.5, isShowLeftText: true, leftText: '售后服务'),
],
),
);
}
}