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(),
    );
  }
}
相关推荐
森之鸟10 分钟前
flutter项目适配鸿蒙
flutter·华为·harmonyos
傅里叶38 分钟前
Flutter在OrangePi 5 Plus上视频播放锁死问题
前端·flutter
书弋江山19 小时前
flutter 跨平台编码库 protobuf 工具使用
android·flutter
程序员老刘·19 小时前
Flutter 3.35 更新要点解析
flutter·ai编程·跨平台开发·客户端开发
tangweiguo0305198719 小时前
Flutter vs Android:页面生命周期对比详解
flutter
tangweiguo0305198719 小时前
Flutter网络请求实战:Retrofit+Dio完美解决方案
flutter
来来走走1 天前
Flutter开发 webview_flutter的基本使用
android·flutter
落魄的Android开发1 天前
Flutter以模块化适配 HarmonyOS方案的实现步骤
flutter
tangweiguo030519871 天前
Flutter GetX 全面指南:状态管理、路由与依赖注入的最佳实践
flutter
来来走走1 天前
Flutter Form组件的基本使用
android·flutter