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(),
    );
  }
}
相关推荐
不爱吃糖的程序媛4 小时前
Flutter 与 OpenHarmony 通信:Flutter Channel 使用指南
前端·javascript·flutter
用户66116655296527 小时前
Futter3 仿抖音我的页面or用户详情页
flutter
Haha_bj7 小时前
Flutter ——device_info_plus详解
android·flutter·ios
前端小伙计7 小时前
Android/Flutter 项目统一构建配置最佳实践
android·flutter
微祎_8 小时前
Flutter for OpenHarmony:形状拼图游戏开发全指南 - 基于Flutter CustomPaint的可拖拽矢量拼图实现与设计理念
flutter
不爱吃糖的程序媛8 小时前
解锁Flutter鸿蒙开发新姿势——flutter_ohfeatures插件集实战指南
flutter
一只大侠的侠9 小时前
React Native开源鸿蒙跨平台训练营 Day16自定义 useForm 高性能验证
flutter·开源·harmonyos
子春一9 小时前
Flutter for OpenHarmony:绿氧 - 基于Flutter的呼吸训练应用开发实践与身心交互设计
flutter·交互
ujainu9 小时前
告别杂乱!Flutter + OpenHarmony 鸿蒙记事本的标签与分类管理(三)
android·flutter·openharmony
ZH154558913110 小时前
Flutter for OpenHarmony Python学习助手实战:API接口开发的实现
python·学习·flutter