Flutter水波纹效果

该博客详细解析了如何在Flutter中创建一个自定义的ACEWaterButton,该按钮具有水波纹动画效果。通过使用AnimationController和CustomPainter,实现了内外两个矩形的叠加,外置矩形根据时间进度改变透明度,从而形成水波纹扩散的效果。博客提供了完整的代码示例,支持自定义颜色、内置和外置矩形的宽高以及动画时长。
摘要由CSDN通过智能技术生成

一、预览

参考:Flutter 133: 图解自定义 ACEWaterButton 水波纹按钮

在这里插入图片描述

二、分析

  • 内置圆为固定宽高矩形
  • 使用AnimationController获取时间进度
  • 外置圆为Paint绘制的动态宽高矩形,根据时间进度逐步更新透明度
  • Stack叠加内置矩形和外置矩形

1 内置矩形

Container(
  height: widget.innerHigh,
  width: widget.innerWidth,
  decoration: BoxDecoration(
    color: Colors.red,
    borderRadius: BorderRadius.circular(20.0)
  )
)

2 水波纹

(1) 动画

当创建一个AnimationController时,需要传递一个vsync参数,它接收一个TickerProvider类型的对象,它的职责是创建Ticker。通常我们会讲SingleTickerProvideStateMixin添加到State的定义中,然后将State对象作为vsync的值。

片段如下:

class _ACEWaterButtonState extends State<ACEWaterButton>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
        vsync: this, duration: widget.duration ?? Duration(milliseconds: 2000))
      ..repeat();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  ...
(2) 画水波纹矩形
class ACEWaterPainter extends CustomPainter {
  final double progress;
  final Color color;
  final double innerWidth;
  final double innerHigh;
  final double outerWidth;
  final double outerHigh;

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

  ACEWaterPainter(this.progress, this.color, this.innerWidth, this.innerHigh, this.outerWidth, this.outerHigh);

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

    double _changeW = innerWidth + (outerWidth - innerWidth) * progress;
    double _changeH = innerHigh + (outerHigh - innerHigh) * progress;

    canvas.translate(size.width/2, size.height/2);
    canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromCenter(center: Offset(0, 0), width: _changeW, height: _changeH), Radius.circular(20.0)), _paint);
  }

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

三、完整代码

目前支持自定义如下参数

外置矩形宽高(可选,默认内置矩形2倍)

内置矩形宽高

颜色

单次时长(可选,默认2s)

import 'package:flutter/material.dart';

class ACEWaterButton extends StatefulWidget {
  final double innerWidth;
  final double innerHigh;
  final double? outerWidth;
  final double? outerHigh;
  final Color color;
  final Duration? duration;

  const ACEWaterButton(this.color,
      {this.innerWidth = 68.0, this.innerHigh = 48.0, this.duration, this.outerWidth, this.outerHigh});

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

class _ACEWaterButtonState extends State<ACEWaterButton>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
        vsync: this, duration: widget.duration ?? Duration(milliseconds: 2000))
      ..repeat();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Stack(
          alignment: Alignment.center,
          children: [
            CustomPaint(
                size: Size(widget.outerWidth ?? widget.innerWidth * 2, widget.outerHigh ?? widget.innerHigh * 2),
                painter: ACEWaterPainter(_controller.value, widget.color,
                    widget.innerWidth, widget.innerHigh, widget.outerWidth ?? widget.innerWidth * 2, widget.outerHigh ?? widget.innerHigh * 2)
            ),
            Container(
              height: widget.innerHigh,
              width: widget.innerWidth,
              decoration: BoxDecoration(
                color: widget.color,
                borderRadius: BorderRadius.circular(20.0)
              ),
            ),
          ],
        );
      }
    );
  }
}

class ACEWaterPainter extends CustomPainter {
  final double progress;
  final Color color;
  final double innerWidth;
  final double innerHigh;
  final double outerWidth;
  final double outerHigh;

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

  ACEWaterPainter(this.progress, this.color, this.innerWidth, this.innerHigh, this.outerWidth, this.outerHigh);

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

    double _changeW = innerWidth + (outerWidth - innerWidth) * progress;
    double _changeH = innerHigh + (outerHigh - innerHigh) * progress;

    canvas.translate(size.width/2, size.height/2);
    canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromCenter(center: Offset(0, 0), width: _changeW, height: _changeH), Radius.circular(20.0)), _paint);
  }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾云鹤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值