老规矩,先上GIF图

Flutter如何动画画出水平水波纹效果

参阅老孟大佬制造水波纹的作用,思考怎么制造一个水平的水波纹。

这儿咱们需要考虑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,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

至此,水平水波纹已经完成了~