Flutter 中如何手动绘制一个水滴球(波浪球)(水滴图)

Flutter 中如何手动绘制一个水滴球(波浪球)(水滴图)

效果预览

本组件实现了一个具有动态波浪效果的液体填充球,支持以下特性:

  • 🌊 可调节的波浪动画速度
  • 🎨 自定义波浪颜色或渐变色
  • 🔢 精确的百分比控制(0.0-1.0)
  • 📏 灵活调整容器尺寸和边距
  • 🖼️ 可定制的圆形边框样式

Pub.dev 发布地址:https://pub.dev/packages/liquid_ball

Github预览图:https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fraw.githubusercontent.com%2FAzad-Zhang%2Fmy_image%2Frefs%2Fheads%2Fmain%2Fliquid_ball.gif&pos_id=img-ZU8IuFBI-1747406058835)

快速开始

1. 基础代码结构(核心代码解析)

// 组件核心结构
LiquidBallWidget(
  waveColor: Colors.blue,   // 单色模式
  percentage: 0.75,         // 填充比例(重要参数)
)
代码说明:
  • 使用 LiquidBallWidget 作为容器
  • waveColor 控制波浪颜色(与 waveGradient 二选一)
  • percentage 是关键控制参数(0.0=空,1.0=满)

2. 完整组件树示例


Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: LiquidBallWidget(
        waveGradient: LinearGradient(
          colors: [Colors.purple[300]!, Colors.blue[200]!],
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
        ),
        containerSize: 150,
        percentage: 0.6,
        containerBorder: Border.all(
          color: Colors.amber,
          width: 2,
          style: BorderStyle.solid,
        ),
      ),
    ),
  );
}
  • 关键代码解析:
    • waveGradient 实现渐变效果(需配合 LinearGradient
    • containerSize 控制整体尺寸(直径长度)
    • containerBorder 自定义边框样式

核心参数深度解析

波浪控制参数

// 在 _LiquidWavePainter 类中
void paint(Canvas canvas, Size size) {
  final baseHeight = size.height * (1 - percentage); // 核心计算公式
  // ...
}
实现原理:
  • percentage 通过 1 - percentage 转换为绘制基准线
  • 示例:当 percentage=0.7 时:
    • 计算基准线:100px 容器 → 100*(1-0.7)=30px 从底部开始
    • 波浪在容器上部 70% 区域波动

动画控制逻辑

// 在 _LiquidBallState 类中
void initState() {
  _waveController = AnimationController(
    vsync: this,
    duration: widget.animationDuration,
  )..repeat(); // 关键动画控制方法
  
  _waveAnimation = _waveController.drive(
    Tween(begin: 0.0, end: 1.0), // 生成0→1的连续值
  );
}
动画流程:
  1. repeat() 方法启动无限循环动画
  2. 每帧通过 _waveAnimation.value 获取当前进度值(0.0-1.0)
  3. 该值传递给 _LiquidWavePainter 驱动波浪运动

高级定制指南

1. 波形特征调整

// 修改 _LiquidWavePainter 类中的常量
const waveAmplitude = 20.0;  // 波浪高度(默认16)
const waveFrequency = 4.0;   // 波浪密度(默认3.5)

// 在_createWavePath方法中:
final radians = (x / size.width * waveFrequency * pi) + (phase * 2 * pi);
final y = baseHeight + waveAmplitude * sin(radians); // 正弦波公式
参数效果:
  • waveAmplitude 增大 → 波浪起伏更剧烈
  • waveFrequency 增大 → 波浪密度更高

2. 动态水位控制

// 示例:实现水位渐变动画
AnimatedLiquidBallWidget({Key? key, required double targetPercentage})
    : super(key: key) {
  // 使用显式动画控制
  _controller = AnimationController(
    duration: const Duration(seconds: 2),
    vsync: this,
  );
  _animation = Tween(begin: 0.0, end: targetPercentage)
      .animate(_controller);
}


Widget build(BuildContext context) {
  return AnimatedBuilder(
    animation: _animation,
    builder: (context, _) {
      return LiquidBallWidget(
        percentage: _animation.value,
        // ...其他参数
      );
    },
  );
}

实现原理图解

绘制流程分解

  1. 容器裁剪

    canvas.clipPath(Path()..addOval(rect)); // 圆形裁剪区域
    
    • 创建圆形绘制区域
    • 限制波浪绘制范围
  2. 波浪路径生成

    for (x in -50...width+50) {
      y = baseHeight + 16 * sin(x/width*3.5π + phase*2π)
    }
    
    • 使用正弦函数生成波浪曲线
    • 添加水平填充防止边缘空隙
  3. 颜色填充

    Paint()
      ..shader = gradient.createShader(rect) // 渐变着色器
      ..color = waveColor                    // 单色模式
    
    • 根据参数选择着色方式
    • 支持线性/径向渐变

参数详解

核心参数

参数类型必填默认值说明
percentagedouble✔️0.5液体填充比例 (0.0-1.0)
waveColorColor✖️null波浪单色(与渐变色二选一)
waveGradientGradient✖️null波浪渐变色(与单色二选一)

样式参数

参数类型默认值说明
containerSizedouble100容器直径
containerPaddingdouble10内边距
containerBorderBorder红色边框容器边框样式

动画参数

参数类型默认值说明
animationDurationDuration2秒完整波浪周期时长

注意事项

1. 参数互斥规则

// 正确用法
waveColor: Colors.blue  // 或单独使用 waveGradient

// 错误用法 ❌
waveColor: Colors.blue,
waveGradient: myGradient  // 同时设置会抛出异常

2. 性能优化建议

  • 避免在动画过程中频繁重建组件
  • 当需要高频更新时,考虑将动画控制器提升到上层
  • 对于复杂渐变,建议预创建 Gradient 对象

完整示例代码

import 'package:flutter/material.dart';

class DemoPage extends StatefulWidget {
  
  _DemoPageState createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  double _currentLevel = 0.3;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Liquid Ball Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            LiquidBallWidget(
              waveGradient: LinearGradient(
                colors: [Colors.teal, Colors.cyan],
                stops: [0.3, 1.0],
              ),
              percentage: _currentLevel,
              containerSize: 180,
              containerBorder: Border.all(
                color: Colors.indigo,
                width: 3,
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => setState(() {
                _currentLevel = (_currentLevel + 0.1).clamp(0.0, 1.0);
              }),
              child: Text('Add 10%'),
            )
          ],
        ),
      ),
    );
  }
}

常见问题解答

Q:如何实现垂直方向上的波浪效果?
A:修改绘制逻辑,将正弦波应用在Y轴方向,调整坐标计算方式

Q:能否支持不规则容器形状?
A:修改 clipPath 的裁剪路径即可支持任意形状

Q:动画出现卡顿怎么优化?
A:尝试以下方法:

  1. 减少波浪频率值
  2. 降低动画帧率
  3. 使用性能更好的渐变类型

Q:如何添加水面反光效果?
A:可在现有绘制逻辑基础上叠加半透明高光层,使用二次贝塞尔曲线创建反光形状


本组件已在 Flutter 3.13 版本测试通过,如有任何使用问题或改进建议,欢迎在评论区留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值