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(),
    );
  }
}
相关推荐
向哆哆3 小时前
打造高校四六级报名管理系统:基于 Flutter × OpenHarmony 的跨端开发实践
flutter·开源·鸿蒙·openharmony·开源鸿蒙
2501_940007893 小时前
Flutter for OpenHarmony三国杀攻略App实战 - 设置功能实现
flutter
lbb 小魔仙4 小时前
【Harmonyos】开源鸿蒙跨平台训练营DAY9:获取分类数据并渲染
flutter·华为·harmonyos
mocoding4 小时前
Flutter 3D 翻转动画flip_card三方库在鸿蒙版天气预报卡片中的实战教程
flutter·3d·harmonyos
2601_949809595 小时前
flutter_for_openharmony家庭相册app实战+我的Tab实现
java·javascript·flutter
2601_949868366 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
一起养小猫7 小时前
Flutter for OpenHarmony 实战:别踩白方块游戏完整开发指南
flutter·游戏
●VON8 小时前
Flutter for OpenHarmony 21天训练营 Day03 总结:从学习到输出,迈出原创第一步
学习·flutter·openharmony·布局·技术
程序员清洒8 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6669 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart