参考:Flutter 133: 图解自定义 ACEWaterButton 水波纹按钮
Container(
height: widget.innerHigh,
width: widget.innerWidth,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20.0)
)
)
当创建一个AnimationController
时,需要传递一个vsync参数,它接收一个TickerProvider
类型的对象,它的职责是创建Ticker
。通常我们会讲SingleTickerProvideStateMixin
添加到State
的定义中,然后将State
对象作为vsync
的值。
片段如下:
class _ACEWaterButtonState extends State
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();
}
...
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
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;
}