dependencies:
flutter_star: $lastVersion
複製程式碼
一、描述
目標: 使用canvas手工打造,一個完美的星星評分元件。
---->[StarScore 星星顯示元件]----
[1] 比如顯示4.2: 會有5顆星, 前四顆填滿,後一刻填充20%
StarScore 為 Stateless元件,僅負責顯示的需求
---->[CustomRating 星星評分元件]----
[2] 可指定最大值,也就是顯示多少個星星
[3] 點選時會改變狀態,進行評分,支援半星評分
[4] 支援評分回撥
---->[Star元件]----
[5]. 可定義星星的顯示進度情況 0% ~ 100 % 無死角
[6]. 可定義星星的角數
[7]. 可定義星星的顏色、大小
複製程式碼
二 、StarScore
分數展示元件
名稱 | 型別 | 功能 | 備註 | 預設 |
---|---|---|---|---|
score | double | 分數 | - | 0 |
star | Star | 見 第四點 |
星星屬性配置 | Star() |
tail | Widget | 尾部的元件 | - | null |
StarScore(
score: 4.8,
star: Star(
fillColor: Colors.tealAccent,
emptyColor: Colors.grey.withAlpha(88)),
tail: Column(
children: <Widget>[
Text("綜合評分"),
Text("4.8"),
],
),
),
複製程式碼
三 、CustomRating
評分元件
名稱 | 型別 | 功能 | 備註 | 預設 |
---|---|---|---|---|
max | int | 最大星星數 | - | 5 |
score | double | 分數 | - | 0 |
star | Star | 見 第四點 |
星星屬性配置 | Star() |
onRating | Fluction(double) | 點選回撥 | @required | null |
1.最簡使用
CustomRating(onRating: (s) {
print(s);
}),
複製程式碼
2.可高度定製
CustomRating(
max: 6,
score: 3.0,
star: Star(
num: 12,
fillColor: Colors.orangeAccent,
fat: 0.6,
emptyColor: Colors.grey.withAlpha(88)),
onRating: (s) {
print(s);
}),
複製程式碼
四 、Star
星星元件 : 高度可定製的配置類
名稱 | 型別 | 功能 | 備註 | 預設 |
---|---|---|---|---|
progress | double | 填充的進度 | [0,1] | 0.0 |
num | int | 星星的角數 | 大於3 | 5 |
fat | double | 星星的胖瘦 | (0,1] | 0.5 |
emptyColor | Color | 星星的色 | - | Colors.grey |
fillColor | Color | 星星的填充色 | - | Colors.yellow |
size | double | 星星的大小 | - | 20 |
1. 進度填充:progress
2. 星星的角數:num
3. 星星的胖瘦:fat
4. 星星的顏色:fillColor和emptyColor
展示結束,下面進入正文
一 、如何自定義繪製的元件
1.分析元件的需求,抽離出需要配置的屬性
class Star {
final int num;
final double progress;
final Color emptyColor;
final Color fillColor;
final double size;
final double fat;
const Star({this.progress = 0,
this.fat = 0.5,
this.fillColor = Colors.yellow,
this.emptyColor = Colors.grey,
this.num = 5,
this.size = 25});
}
複製程式碼
2. 建立好畫板準備開畫
class _StarPainter extends CustomPainter {
Star star;
Paint _paint;
Paint _filePaint;
Path _path;
double _radius;
_StarPainter(this.star) {
_paint = Paint()
..color = (star.emptyColor)
..isAntiAlias = true;
_filePaint = Paint()
..color = (star.fillColor);
_path = Path();
_radius = star.size / 2.0;
}
@override
void paint(Canvas canvas, Size size) {
//TODO 繪製
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
複製程式碼
3.開畫
如果說StarWidget是評分元件的基礎,那麼繪製的路徑就是星星的靈魂
下面的nStarPath是繪製n角星路徑的核心方法
Path nStarPath(int num, double R, double r, {dx = 0, dy = 0, rotate = 0}) {
_path.reset(); //重置路徑
double perRad = 2 * pi / num; //每份的角度
double radA = perRad / 2 / 2 + rotate; //a角
double radB = 2 * pi / (num - 1) / 2 - radA / 2 + radA + rotate; //起始b角
_path.moveTo(cos(radA) * R + dx, -sin(radA) * R + dy); //移動到起點
for (int i = 0; i < num; i++) {
//迴圈生成點,路徑連至
_path.lineTo(
cos(radA + perRad * i) * R + dx, -sin(radA + perRad * i) * R + dy);
_path.lineTo(
cos(radB + perRad * i) * r + dx, -sin(radB + perRad * i) * r + dy);
}
_path.close();
return _path;
}
複製程式碼
在初始化的時候為路徑賦值
class _StarPainter extends CustomPainter {
...
_StarPainter(this.star) {
...
_path = Path();
_radius = star.size / 2.0;
nStarPath(star.num, _radius, _radius * star.fat);
}
複製程式碼
繪製也非常簡單,其中有個進度問題,可以先畫背景的星星, 再畫一個填充的星星,再用canvas.clipRect進行裁剪即可。
@override
void paint(Canvas canvas, Size size) {
canvas.translate(_radius, _radius);
canvas.drawPath(_path, _paint);
canvas.clipRect(Rect.fromLTRB(
-_radius, -_radius, _radius * 2 * star.progress - _radius, _radius));
canvas.drawPath(_path, _filePaint);
}
複製程式碼
4.自定義元件
將畫板放入CustomPaint中即可
class StarWidget extends StatelessWidget {
final Star star;
StarWidget({this.star = const Star()});
@override
Widget build(BuildContext context) {
return Container(
width: star.size,
height: star.size,
child: CustomPaint(
painter: _StarPainter(star),
),
);
}
}
複製程式碼
這就是星星元件的所有程式碼,也不超過百行。
二 、StarScore的實現
該元件的目的是顯示評分,可以精確的顯示百分進度
其實也沒啥,僅是用幾個StarWidget拼起來而已,程式碼也就下面一丟丟
class StarScore extends StatelessWidget {
final Star star;
final double score;
final Widget tail;
StarScore({this.star = const Star(), this.score, this.tail});
@override
Widget build(BuildContext context) {
var li = <StarWidget>[];
int count = score.floor();
for (int i = 0; i < count; i++) {
li.add(StarWidget(star: star.copyWith(progress: 1.0)));
}
if (score - count > 0) {
li.add(StarWidget(star: star.copyWith(progress: score - count)));
}
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
...li,
SizedBox(
width: 10,
),
if (tail!=null) tail
],
);
}
}
複製程式碼
三 、StarScore的實現
由於點選需要自己響應進行狀態改變,所以使用StatefulWidget 最核心的是GestureDetector進行觸點的獲取並計算出當前值。其中對.5進行處理,以及越界的處理。
class CustomRating extends StatefulWidget {
final int max;
final Star star;
final double score;
final Function(double) onRating;
CustomRating(
{this.max = 5,
this.score = 0,
this.star = const Star(),
@required this.onRating})
: assert(score <= max);
@override
_CustomRatingState createState() => _CustomRatingState();
}
class _CustomRatingState extends State<CustomRating> {
double _score;
@override
void initState() {
_score = widget.score;
super.initState();
}
@override
Widget build(BuildContext context) {
var li = <StarWidget>[];
int count = _score.floor(); //滿星
for (int i = 0; i < count; i++) {
li.add(StarWidget(star: widget.star.copyWith(progress: 1.0)));
}
if (_score != widget.max.toDouble())
li.add(StarWidget(
star: widget.star.copyWith(progress: _score - count))); //不滿星
var empty = widget.max - count - 1; // 空星
for (int i = 0; i < empty; i++) {
li.add(StarWidget(star: widget.star.copyWith(progress: 0)));
}
return GestureDetector(
onTapDown: (d) {
setState(() {
_score = d.localPosition.dx / widget.star.size;
if (_score - _score.floor() > 0.5) {
_score = _score.floor() + 1.0;
} else {
_score = _score.floor() + 0.5;
}
if (_score >= widget.max.toDouble()) {
_score = widget.max.toDouble();
}
widget.onRating(_score);
});
},
child: Wrap(
children: li,
),
);
}
}
複製程式碼
四. 釋出到pub
1.配置
需要在
pubspec.yaml
進行一些配置
name 是名稱
description 是描述 60 ~ 180 之間,太短或太長會扣分
version 版本
author 作者資訊,會報warning 但我就想寫
homepage 主頁
複製程式碼
---->[pubspec.yaml]----
name: flutter_star
description: You can create a star easily and decide how many angle or color of the star, even the fat and progress of the star.
version: 0.1.2
author: 張風捷特烈<1981462002@qq.com>
homepage: https://juejin.im/user/5b42c0656fb9a04fe727eb37/collections
複製程式碼
2.最好寫個example
不然會扣分
它會在這裡,給使用者看
3.釋出到pub
flutter packages pub publish --server=https://pub.dartlang.org
複製程式碼
然後需要許可權驗證,記得
全部複製在瀏覽器開啟,不用在控制檯點連結
,由於控制檯的換行而導致url不全。
然後就看你的網給不給力了。
flutter_star
歡迎使用
尾聲
另外本人有一個Flutter微信交流群,歡迎小夥伴加入,共同探討Flutter的問題,期待與你的交流與切磋。
@張風捷特烈 2019.02.23 未允禁轉
我的公眾號:程式設計之王
聯絡我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~