Flutter动画—涟漪效果

功能分析

  • 涟漪是由几个圆重叠在一起的

  • 外层圆环比内层圆环的背景色要淡,可以改变外层圆的透明度

  • 想要达到涟漪效果只要将每个圆的半径慢慢变大并且循环动画即可

​实现方法

  1. 在画板上创建三个圆环,再实现外层的圆环要比内层圆环的颜色要淡。

    class WaterRipplePainter extends CustomPainter {
    final Paint _paint = Paint()..style = PaintingStyle.fill;
    WaterRipplePainter( );
    int count = 3;
    Color color = const Color(0xFF0080ff);
    @override
    void paint(Canvas canvas, Size size) {
    double radius = min(size.width / 2, size.height / 2);
    for (int i = count; i >= 0; i--) {
    final double opacity = (1.0 - ((i) / (count + 1)));
    final Color _color = color.withOpacity(opacity);
    _paint..color = _color;
    double _radius = radius * ((i) / (count + 1));
    canvas.drawCircle(
    Offset(size.width / 2, size.height / 2), _radius, _paint);
    }
    }

    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
    }
    }
    class TextLiany extends StatelessWidget {
    const TextLiany({super.key});

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    body: Container(
    width: 500,
    height: 500,
    child: CustomPaint(
    painter: WaterRipplePainter(),
    ),
    ),
    );
    }
    }

  1. 使用动画让圆环动起来

    class WaterRipplePainter extends CustomPainter {
    final double progress;
    final Paint _paint = Paint()..style = PaintingStyle.fill;
    WaterRipplePainter(
    this.progress,
    );
    int count = 3;
    Color color = const Color(0xFF0080ff);
    @override
    void paint(Canvas canvas, Size size) {
    double radius = min(size.width / 2, size.height / 2);
    for (int i = count; i >= 0; i--) {
    final double opacity = (1.0 - ((i) / (count + 1)));
    final Color _color = color.withOpacity(opacity);
    _paint..color = _color;
    double _radius = radius * ((i + progress) / (count + 1));
    canvas.drawCircle(
    Offset(size.width / 2, size.height / 2), _radius, _paint);
    }
    }

    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
    }
    }

    class TextLiany extends StatefulWidget {
    const TextLiany({super.key});

    @override
    State<TextLiany> createState() => _TextLianyState();
    }

    class _TextLianyState extends State<TextLiany>
    with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    @override
    void initState() {
    super.initState();
    _controller = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 2000),
    )..repeat();
    }

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

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    body: Center(
    child: AnimatedBuilder(
    animation: _controller,
    builder: (context, child) {
    return Container(
    width: 200,
    height: 200,
    child: CustomPaint(
    painter: WaterRipplePainter(_controller.value),
    ),
    );
    }),
    ),
    );
    }
    }

3.使用上面的代码我们发现圆环能够向外扩散了,但是扩散后会出现卡顿的现象,然后重新开始动画。这是因为我们现在只是改变了每个圆的半径,当我们把圆的背景色也跟随半径变大而更加透明后在视觉上就不会出现这种现象了

只需要改变WaterRipplePainter类即可

复制代码
class WaterRipplePainter extends CustomPainter {
  final double progress;
  final Paint _paint = Paint()..style = PaintingStyle.fill;
  WaterRipplePainter(
    this.progress,
  );
  int count = 3;
  Color color = const Color(0xFF0080ff);
  @override
  void paint(Canvas canvas, Size size) {
    double radius = 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 _color = color.withOpacity(opacity);
      _paint..color = _color;
      double _radius = radius * ((i + progress) / (count + 1));
      canvas.drawCircle(
          Offset(size.width / 2, size.height / 2), _radius, _paint);
    }
  }
 
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

这时候我们的发现不会卡顿了

4.为了后期方便,我们把涟漪个数、涟漪颜色、涟漪动画控制器、涟漪所占宽度等内容全部需要传进来。

完整封装

复制代码
import 'dart:math';
 
import 'package:flutter/material.dart';
 
class WaterRipple extends StatefulWidget {
  const WaterRipple({
    super.key,
    this.count = 3,
    this.color = const Color(0xFF0080ff),
    this.width = 300,
    this.controller,
  });
  final int count; //涟漪的个数
  final Color color; //涟漪的颜色
  final double? width; //涟漪的宽高
  final AnimationController? controller; //涟漪动画控制器
 
  @override
  State<WaterRipple> createState() => _WaterRippleState();
}
 
class _WaterRippleState extends State<WaterRipple>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    _controller = widget.controller != null
        ? widget.controller!
        : AnimationController(
            vsync: this,
            duration: const Duration(milliseconds: 2000),
          )
      ..repeat();
    super.initState();
  }
 
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width,
      height: widget.width,
      child: AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return CustomPaint(
            painter: WaterRipplePainter(
              _controller.value,
              count: widget.count,
              color: widget.color,
            ),
          );
        },
      ),
    );
  }
}
 
class WaterRipplePainter extends CustomPainter {
  final double progress;
  final int count;
  final Color color;
  final Paint _paint = Paint()..style = PaintingStyle.fill;
  WaterRipplePainter(
    this.progress, {
    this.count = 3,
    this.color = const Color(0xFF0080ff),
  });
  @override
  void paint(Canvas canvas, Size size) {
    double radius = 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 _color = color.withOpacity(opacity);
      _paint..color = _color;
      double _radius = radius * ((i + progress) / (count + 1));
      canvas.drawCircle(
          Offset(size.width / 2, size.height / 2), _radius, _paint);
    }
  }
 
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
 
class TextLiany extends StatefulWidget {
  const TextLiany({super.key});
 
  @override
  State<TextLiany> createState() => _TextLianyState();
}
 
class _TextLianyState extends State<TextLiany>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 2000),
    )..repeat();
  }
 
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: WaterRipple(),
    );
  }
}
相关推荐
song50114 分钟前
多卡训练加速:HCCL 集合通信实战
分布式·python·flutter·ci/cd·分类
风清云淡_A6 小时前
【Flutter3.8x】flutter从入门到实战基础教程(一):新建一个flutter项目
flutter
1001101_QIA6 小时前
Flutter 开发报错:Android cmdline-tools 缺失 环境排查与完整修复方案
android·flutter
SoaringHeart20 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
程序员老刘1 天前
Flutter 3.44 有哪些变化?(官方blog完整翻译)
flutter·ai编程·客户端
山屿落星辰1 天前
Flutter 企业级架构设计实战:Clean Architecture + 分层模块化 + 依赖注入全解析
flutter
山屿落星辰1 天前
Flutter 高级特性实战:动画、自定义绘制、平台通道与 Web 优化
前端·flutter
程序软件分享1 天前
2026旗舰版 Java+Flutter 期货微交易系统源码全开源多语言平台
flutter·交易所源码·微盘源码·微交易源码
飞龙14775657467501 天前
Flutter 安全存储插件全面解析:从入门到进阶
flutter