前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Flutter 专题】133 图解自定义 ACEWaterButton 水波纹按钮

【Flutter 专题】133 图解自定义 ACEWaterButton 水波纹按钮

作者头像
阿策小和尚
发布2021-08-25 10:24:48
7430
发布2021-08-25 10:24:48
举报
文章被收录于专栏:阿策小和尚阿策小和尚

和尚想自定义一个水波纹按钮,即默认向外扩散的水波样式;实现方式有很多种,和尚尝试最基本的 AnimationController 逐层绘制来处理,和尚简单记录一下尝试过程;

ACEWaterButton

和尚画了一个简单的图如下,预期的水波纹按钮包括两层,以中心圆(蓝色)为基础逐步向外围扩散至(绿色),并循环重复;

1. 内置圆

和尚以此分为两步,第一步先绘制内置圆和内置图标,和尚提供了 innerSizeinnerIcon 属性以方便内置圆的样式自定义;通过 ClipOval 裁切一个完整的内置圆;

其中需要注意的是,内置圆应置于外围圆的中心,因此和尚添加一个 outSize 属性限制外围圆尺寸,同时默认设置 innerSize = 48.0,若未设置 outSize,则以 innerSize * 2 为默认值;

代码语言:javascript
复制
Container(
    width: widget.outSize ?? widget.innerSize * 2,
    height: widget.outSize ?? widget.innerSize * 2,
    child: widget.innerIcon == null
        ? Container() : Center(child: ClipOval(
                child: Container(
                    width: widget.innerSize,
                    height: widget.innerSize,
                    color: widget.color,
                    child: widget.innerIcon))))

2. 水波纹

和尚预想实现水波纹效果则必然离不开 Animation 动画,使用动画方式也有多种,可以继承 AnimatedWidget 也可以使用 AnimationController 自定义动画样式;

和尚预期水波纹不仅范围逐渐变大,并且在扩散过程中透明度逐渐降低,至外围最大范围为止消失;和尚采用最基本的 CustomPainter 自定义 Canvas.drawCircle,根据时间进度来逐层绘制水波纹;

2.1 透明度

和尚使用 Paint 绘制时根据 AnimationController.value 进度逐步设置 color.withOpacity 透明度逐渐变低;

代码语言:javascript
复制
Paint _paint = Paint()..style = PaintingStyle.fill;
_paint..color = color.withOpacity(1.0 - progress);
2.2 外围圆

外围圆主要是根据 AnimationController.value 进度逐步进行半径的更新;和尚预期的水波纹范围只有默认的内置圆到外围圆的范围渐变,因此变动范围为 (outSize - innerSize) * 0.5 * progress,同时起始位置为内置圆,因此初始半径应再加上内置圆半径;

代码语言:javascript
复制
double _radius = ((outSize ?? innerSize * 2) * 0.5 - innerSize * 0.5) * progress + innerSize * 0.5;
canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), _radius, _paint);

和尚在测试过程中也尝试了其他的扩展范围,若起始位置为中心则无需添加内置圆半径;若想增大或见效水波纹范围可以自由调整 AnimationController.value 进度范围;

代码语言:javascript
复制
// 中心点扩展
double _radius = innerSize * 0.5 * progress;
// 增大扩展范围
double _radius = innerSize * 2 * progress;
代码语言:javascript
复制
class ACEWaterPainter extends CustomPainter {
  final double progress;
  final Color color;
  final double innerSize;
  final double outSize;

  Paint _paint = Paint()..style = PaintingStyle.fill;

  ACEWaterPainter(this.progress, this.color, this.innerSize, this.outSize);

  @override
  void paint(Canvas canvas, Size size) {
    _paint..color = color.withOpacity(1.0 - progress);

    double _radius =
        ((outSize ?? innerSize * 2) * 0.5 - innerSize * 0.5) * progress + innerSize * 0.5;

    canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), _radius, _paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

3. 小反思

3.1 内置圆是否可缺省?

和尚在通过 ACEWaterPainter 绘制水波纹过程中,起始位置从内置圆开始,那是否可以省略第一步的内置圆呢?

暂时先不缺省,因为和尚在设置水波纹扩散过程中,同时设置了透明度的渐变,若缺省内置圆会影响 innerIcon 的展示效果;但内置圆绘制位置可以调整,也可以在 ACEWaterPainter 中进行绘制;

3.2 shouldRepaint 是否需要一直重绘?

ACEWaterPainter 中是否需要一直重绘;在使用自定义 Paint 委托类创建新的 CustomPaint 对象时若新实例与旧实例不同,则应返回 true,否则应返回 false;因此在水波纹过程中,和尚默认设置为 true 进行重绘;


ACEWaterButton 案例源码


和尚对 ACEWaterButton 水波纹按钮的简单效果已满足,但还不够完善,对于重绘的机制还需要优化;如有错误,请多多指导!

来源:阿策小和尚

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阿策小和尚 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ACEWaterButton
    • 1. 内置圆
      • 2. 水波纹
        • 2.1 透明度
        • 2.2 外围圆
      • 3. 小反思
        • 3.1 内置圆是否可缺省?
        • 3.2 shouldRepaint 是否需要一直重绘?
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档