generatePath method
Generates the actual path for the bubble shape including the arrow.
Creates a rounded rectangle with an arrow extending from one of its sides. The implementation uses quadratic Bézier curves for smooth rounded corners and calculates spacing to accommodate the arrow based on its position.
The method handles four different arrow positions:
- Top: Arrow extends upward from the top edge
- Bottom: Arrow extends downward from the bottom edge
- Left: Arrow extends leftward from the left edge
- Right: Arrow extends rightward from the right edge
rect
- The bounding rectangle that defines the drawing area.
Returns a Path object with the bubble's geometric outline including the arrow.
Implementation
Path generatePath({required Rect rect}) {
final Path path = new Path();
double topLeftDiameter = max(borderRadius, 0);
double topRightDiameter = max(borderRadius, 0);
double bottomLeftDiameter = max(borderRadius, 0);
double bottomRightDiameter = max(borderRadius, 0);
final double spacingLeft = this.position == BubblePosition.Left
? arrowHeight
: 0;
final double spacingTop = this.position == BubblePosition.Top
? arrowHeight
: 0;
final double spacingRight = this.position == BubblePosition.Right
? arrowHeight
: 0;
final double spacingBottom = this.position == BubblePosition.Bottom
? arrowHeight
: 0;
final double left = spacingLeft + rect.left;
final double top = spacingTop + rect.top;
final double right = rect.right - spacingRight;
final double bottom = rect.bottom - spacingBottom;
final double centerX = (rect.left + rect.right) * arrowPositionPercent;
path.moveTo(left + topLeftDiameter / 2.0, top);
//LEFT, TOP
if (position == BubblePosition.Top) {
path.lineTo(centerX - arrowWidth, top);
path.lineTo(centerX, rect.top);
path.lineTo(centerX + arrowWidth, top);
}
path.lineTo(right - topRightDiameter / 2.0, top);
path.quadraticBezierTo(right, top, right, top + topRightDiameter / 2);
//RIGHT, TOP
if (position == BubblePosition.Right) {
path.lineTo(
right,
bottom - (bottom * (1 - arrowPositionPercent)) - arrowWidth,
);
path.lineTo(rect.right, bottom - (bottom * (1 - arrowPositionPercent)));
path.lineTo(
right,
bottom - (bottom * (1 - arrowPositionPercent)) + arrowWidth,
);
}
path.lineTo(right, bottom - bottomRightDiameter / 2);
path.quadraticBezierTo(
right,
bottom,
right - bottomRightDiameter / 2,
bottom,
);
//RIGHT, BOTTOM
if (position == BubblePosition.Bottom) {
path.lineTo(centerX + arrowWidth, bottom);
path.lineTo(centerX, rect.bottom);
path.lineTo(centerX - arrowWidth, bottom);
}
path.lineTo(left + bottomLeftDiameter / 2, bottom);
path.quadraticBezierTo(left, bottom, left, bottom - bottomLeftDiameter / 2);
//LEFT, BOTTOM
if (position == BubblePosition.Left) {
path.lineTo(
left,
bottom - (bottom * (1 - arrowPositionPercent)) + arrowWidth,
);
path.lineTo(rect.left, bottom - (bottom * (1 - arrowPositionPercent)));
path.lineTo(
left,
bottom - (bottom * (1 - arrowPositionPercent)) - arrowWidth,
);
}
path.lineTo(left, top + topLeftDiameter / 2);
path.quadraticBezierTo(left, top, left + topLeftDiameter / 2, top);
path.close();
return path;
}