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.width和size.height,适配任意气泡尺寸 - 可配置参数:将圆角半径、尾巴大小、气泡颜色做成可配置参数,方便复用和调整
- 优化重绘逻辑:
shouldRepaint只在参数变化时才重绘,提升性能 - 自然曲线尾巴:气泡尾巴的贝塞尔曲线更贴合设计,且位置始终固定在右下角,不会随尺寸偏移
效果对比
聊天气泡样式:
长消息下的气泡效果:
内容的提问来源于stack exchange,提问作者Sohail Anwar




