You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中绘制钟形曲线以实现目标均衡器图形?

在Flutter中绘制钟形曲线风格的均衡器图形

核心思路:用高斯函数生成钟形曲线点

你参考的示例图里的均衡器柱体,本质是**钟形曲线(高斯曲线)**的变形。比起手动调贝塞尔曲线控制点,直接用高斯函数计算曲线上的点再连线填充,能更精准还原自然的对称衰减效果。

高斯函数的基础公式是:
y = a * e^(-((x - b)^2)/(2*c^2))
参数说明:

  • a:控制曲线的最大高度(对应均衡器的音量强度)
  • b:控制曲线的中心X坐标(对应均衡器的频段位置)
  • c:控制曲线的宽度(对应频段的覆盖范围)

具体实现步骤

1. 编写高斯曲线点生成工具函数

先实现一个函数,根据参数生成曲线上的采样点集:

import 'dart:math' as math;

List<Offset> generateGaussianCurvePoints({
  required double centerX,
  required double maxHeight,
  required double width,
  required double canvasHeight,
  int pointCount = 50,
}) {
  final points = <Offset>[];
  // 取3倍宽度作为曲线左右边界,超出后y值趋近于0,无需计算
  final startX = centerX - width * 3;
  final endX = centerX + width * 3;
  final step = (endX - startX) / pointCount;

  for (var i = 0; i <= pointCount; i++) {
    final x = startX + step * i;
    // 计算高斯曲线y值,转换为Flutter画布坐标系(y轴向下)
    final exponent = -((x - centerX) * (x - centerX)) / (2 * width * width);
    final y = canvasHeight - maxHeight * math.exp(exponent);
    points.add(Offset(x, y));
  }
  return points;
}

2. 在CustomPainter中绘制均衡器

拿到点集后,构建闭合路径并填充,批量绘制多频段的均衡器柱:

class EqualizerPainter extends CustomPainter {
  final List<double> frequencyValues; // 各频段高度比例,范围0-1

  EqualizerPainter(this.frequencyValues);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blueAccent
      ..style = PaintingStyle.fill;

    final columnGap = size.width * 0.1; // 柱体间的间隙比例
    final columnWidth = (size.width - columnGap * (frequencyValues.length - 1)) / frequencyValues.length;
    final widthCoeff = columnWidth * 0.3; // 控制单条曲线的宽窄

    for (var i = 0; i < frequencyValues.length; i++) {
      final centerX = columnGap * i + columnWidth * i + columnWidth / 2;
      final maxHeight = size.height * frequencyValues[i];
      final curvePoints = generateGaussianCurvePoints(
        centerX: centerX,
        maxHeight: maxHeight,
        width: widthCoeff,
        canvasHeight: size.height,
      );

      // 构建闭合路径:曲线点 + 底部左右点
      final path = Path()
        ..addPolygon(curvePoints, false)
        ..lineTo(curvePoints.last.dx, size.height)
        ..lineTo(curvePoints.first.dx, size.height)
        ..close();

      canvas.drawPath(path, paint);
    }
  }

  @override
  bool shouldRepaint(covariant EqualizerPainter oldDelegate) {
    return oldDelegate.frequencyValues != frequencyValues;
  }
}

3. 在Widget中使用CustomPaint展示

直接传入频段高度数据即可渲染:

CustomPaint(
  size: const Size(350, 180),
  painter: EqualizerPainter([0.7, 0.4, 0.9, 0.5, 0.6, 0.3]),
)

备选:用贝塞尔曲线模拟钟形效果

如果坚持用贝塞尔曲线,可通过两条三次贝塞尔曲线模拟单条柱体,但需要手动调整控制点位置,效果精度不如高斯函数:

Path buildBezierEqualizerColumn(Offset center, double height, double width) {
  final bottomLeft = Offset(center.dx - width, center.dy);
  final topLeftControl = Offset(center.dx - width * 0.5, center.dy - height * 0.8);
  final topCenter = Offset(center.dx, center.dy - height);

  final bottomRight = Offset(center.dx + width, center.dy);
  final topRightControl = Offset(center.dx + width * 0.5, center.dy - height * 0.8);

  return Path()
    ..moveTo(bottomLeft.dx, bottomLeft.dy)
    ..cubicTo(topLeftControl.dx, topLeftControl.dy, topCenter.dx, topCenter.dy, topCenter.dx, topCenter.dy)
    ..cubicTo(topCenter.dx, topCenter.dy, topRightControl.dx, topRightControl.dy, bottomRight.dx, bottomRight.dy)
    ..close();
}

内容的提问来源于stack exchange,提问作者starry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 04:20:19