前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【 开源计划 - Flutter组件 】 星星也可以如此闪耀 flutter_star

【 开源计划 - Flutter组件 】 星星也可以如此闪耀 flutter_star

作者头像
张风捷特烈
发布2020-04-30 12:05:40
9690
发布2020-04-30 12:05:40
举报
文章被收录于专栏:Android知识点总结

pub地址 】 【github地址

代码语言:javascript
复制
dependencies:
  flutter_star: $lastVersion

一、描述

目标: 使用canvas手工打造,一个完美的星星评分组件。

代码语言:javascript
复制
---->[StarScore 星星显示组件]----
[1] 比如显示4.2: 会有5颗星, 前四颗填满,后一刻填充20%
StarScore 为 Stateless组件,仅负责显示的需求

---->[CustomRating 星星评分组件]----
[2] 可指定最大值,也就是显示多少个星星
[3] 点击时会改变状态,进行评分,支持半星评分
[4] 支持评分回调

---->[StarWidget组件]----
[5]. 可定义星星的显示进度情况 0% ~ 100 % 无死角
[6]. 可定义星星的角数
[7]. 可定义星星的颜色、大小 

二 、StarScore

分数展示组件

名称

类型

功能

备注

默认

score

double

分数

-

0

star

Star

见 第四点

星星属性配置

Star()

tail

Widget

尾部的组件

-

null

代码语言:javascript
复制
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.最简使用
代码语言:javascript
复制
CustomRating(onRating: (s) {
   print(s);
 }),

2.可高度定制
代码语言:javascript
复制
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.分析组件的需求,抽离出需要配置的属性
代码语言:javascript
复制
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. 创建好画板准备开画
代码语言:javascript
复制
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角星路径的核心方法

代码语言:javascript
复制
  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;
  }

在初始化的时候为路径赋值

代码语言:javascript
复制
class _StarPainter extends CustomPainter {
 ...
  _StarPainter(this.star) {
    ...
    _path = Path();
    _radius = star.size / 2.0;
    nStarPath(star.num, _radius, _radius * star.fat);
  }

绘制也非常简单,其中有个进度问题,可以先画背景的星星, 再画一个填充的星星,再用canvas.clipRect进行裁剪即可。

代码语言:javascript
复制
  @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中即可

代码语言:javascript
复制
 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拼起来而已,代码也就下面一丢丢

代码语言:javascript
复制
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进行处理,以及越界的处理。

代码语言:javascript
复制
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进行一些配置

代码语言:javascript
复制
name 是名称
description 是描述 60 ~ 180 之间,太短或太长会扣分
version 版本
author 作者信息,会报warning 但我就想写
homepage 主页
代码语言:javascript
复制
---->[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
代码语言:javascript
复制
flutter packages pub publish --server=https://pub.dartlang.org

然后需要权限验证,记得全部复制在浏览器打开,不用在控制台点链接,由于控制台的换行而导致url不全。

然后就看你的网给不给力了。flutter_star 欢迎使用

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020年02月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、描述
  • 二 、StarScore
  • 三 、CustomRating
    • 1.最简使用
      • 2.可高度定制
      • 四 、Star
        • 1. 进度填充:progress
          • 2. 星星的角数:num
            • 3. 星星的胖瘦:fat
              • 4. 星星的颜色:fillColor和emptyColor
              • 一 、如何自定义绘制的组件
                • 1.分析组件的需求,抽离出需要配置的属性
                  • 2. 创建好画板准备开画
                    • 3.开画
                    • 4.自定义组件
                    • 二 、StarScore的实现
                    • 三 、StarScore的实现
                    • 四. 发布到pub
                      • 1.配置
                        • 2.最好写个example
                          • 3.发布到pub
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档