You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Flutter中如何创建自适应的曲线形聊天气泡?

响应式曲线聊天气泡实现方案

你的问题核心是所有路径坐标都用了固定数值,没有基于气泡的实际尺寸动态计算,导致尺寸变化时形状完全错位。下面是修改后的响应式实现:

修改后的代码

class SendBubbleCustomPainter extends CustomPainter {
  final Color color;
  final double borderRadius;
  final double tailSize;

  SendBubbleCustomPainter({
    this.color = Colors.white,
    this.borderRadius = 12.0,
    this.tailSize = 12.0,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final Path path = Path();
    final double width = size.width;
    final double height = size.height;

    // 从右上角圆角起点开始
    path.moveTo(width - borderRadius, 0);
    // 顶部圆角
    path.arcToPoint(
      Offset(width, borderRadius),
      radius: Radius.circular(borderRadius),
      clockwise: false,
    );
    // 右侧边(预留尾巴位置)
    path.lineTo(width, height - borderRadius - tailSize);
    // 绘制气泡尾巴的贝塞尔曲线
    path.cubicTo(
      width, height - borderRadius,
      width + tailSize * 0.7, height - borderRadius * 0.5,
      width + tailSize, height,
    );
    path.cubicTo(
      width + tailSize * 0.8, height,
      width + tailSize * 0.5, height - borderRadius * 0.3,
      width, height - borderRadius,
    );
    // 右下角圆角
    path.arcToPoint(
      Offset(width - borderRadius, height),
      radius: Radius.circular(borderRadius),
      clockwise: false,
    );
    // 底部边到左下角
    path.lineTo(borderRadius, height);
    // 左下角圆角
    path.arcToPoint(
      Offset(0, height - borderRadius),
      radius: Radius.circular(borderRadius),
      clockwise: false,
    );
    // 左侧边到左上角
    path.lineTo(0, borderRadius);
    // 左上角圆角
    path.arcToPoint(
      Offset(borderRadius, 0),
      radius: Radius.circular(borderRadius),
      clockwise: false,
    );
    // 闭合路径
    path.close();

    final Paint paint = Paint()
      ..style = PaintingStyle.fill
      ..color = color;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant SendBubbleCustomPainter oldDelegate) {
    return oldDelegate.color != color ||
        oldDelegate.borderRadius != borderRadius ||
        oldDelegate.tailSize != tailSize;
  }
}

关键优化点

  • 动态坐标计算:所有路径点都基于传入的size.widthsize.height,适配任意气泡尺寸
  • 可配置参数:将圆角半径、尾巴大小、气泡颜色做成可配置参数,方便复用和调整
  • 优化重绘逻辑shouldRepaint只在参数变化时才重绘,提升性能
  • 自然曲线尾巴:气泡尾巴的贝塞尔曲线更贴合设计,且位置始终固定在右下角,不会随尺寸偏移

效果对比

聊天气泡样式:
聊天气泡样式截图

长消息下的气泡效果:
长消息下的气泡效果截图

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

火山引擎 最新活动