老规矩,先上GIF图
参阅老孟大佬制造水波纹的作用,思考怎么制造一个水平的水波纹。
这儿咱们需要考虑3点:
- 水波纹得是水平作用
- 水波纹是由中心分散到周围
- 水波纹是逐步削弱的
所以咱们先画一个水波纹,通过操控圆的巨细来操控分散过程,在分散的一起增加透明度实现削弱作用。下面讲怎么做成水平的作用。
import 'package:flutter/material.dart';
import 'dart:math';
class RippleAnimatedWidget extends StatefulWidget {
final Color color;
final AnimationController controller;
const RippleAnimatedWidget({super.key, this.color = Colors.white, required this.controller});
@override
State<StatefulWidget> createState() => _RippleAnimatedWidgetState();
}
class _RippleAnimatedWidgetState extends State<RippleAnimatedWidget>
with SingleTickerProviderStateMixin {
late Animation<double> animation;
@override
void initState() {
super.initState();
//增加一个缓出的作用
animation = CurvedAnimation(
parent: widget.controller,
curve: const Interval(0.5, 1, curve: Curves.easeOut));
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: widget.controller,
builder: (context, child) {
return CustomPaint(
painter: RipplePainter(widget.controller.value, color: widget.color, count: 3),
);
},
);
}
}
class RipplePainter extends CustomPainter {
final int count;
final double progress;
final Color color;
Paint painter = Paint()..style = PaintingStyle.stroke..strokeWidth = 2;
RipplePainter(this.progress, {this.color = Colors.white, this.count = 1});
@override
void paint(Canvas canvas, Size size) {
double width = min(size.width / 2, size.height / 2);
for (int i = count; i >= 0; i--) {
//改动透明度
final double opacity = (1.0 - ((i + progress) / (count + 1)));
final Color tmpColor = color.withOpacity(opacity);
painter.color = tmpColor;
//宽度递增
double radius = width * ((i + progress) / (count + 1));
canvas.drawCircle(
Offset(size.width / 2, size.height / 2), radius, painter);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
接下来就是把水波纹做成水平的
这儿首要想到的是运用Transform
做偏移,果不其然,它可以让竖向的Widget转换成横向,那么咱们就可以把RippleAnimatedWidget
做偏移。
Transform
的源码
/// Creates a widget that transforms its child.
///
/// The [transform] argument must not be null.
const Transform({
super.key,
required this.transform,
this.origin,
this.alignment,
this.transformHitTests = true,
this.filterQuality,
super.child,
}) : assert(transform != null);
其间起到关键作用的就是transform
,它的类型是Matrix4
,官方文档介绍
Matrix4.identity()..setEntry(1, 1, 0.2)
具体意思是
1、Matrix4.identity() 创立生成一个矩阵
2、setEntry(int row, int col, double v) 设置矩阵中的行、列、视图距离,第三个的视图距离相当于对着屏幕的远近,当越远时就看着此物体就会越全面,看着就如3D全体作用一样。
3、rotateX(angle),rotateY(angle),rotateZ(angle) 分别设置改动XYZ轴方向
这儿由于咱们只需要做视距调整,不需要做坐标轴的转换,所以只需要做如下实现
Transform(
transform: Matrix4.identity()..setEntry(1, 1, 0.2),
alignment: FractionalOffset.center,
child: RippleAnimatedWidget(
color: Colors.white,
controller: animationController,
),
)
加上创立一个AnimationController
,重复执行即可
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
late AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1300),
)..repeat();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(50),
color: Colors.black,
width: double.infinity,
height: double.infinity,
alignment: Alignment.center,
child: Stack(
children: <Widget>[
SizedBox(
width: 400,
height: 400,
child: Transform(
transform: Matrix4.identity()..setEntry(1, 1, 0.2),
alignment: FractionalOffset.center,
child: RippleAnimatedWidget(
color: Colors.white,
controller: animationController,
),
),
)
],
),
),
);
}
}
至此,水平水波纹已经完成了~