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