Search code examples
objective-ciosquartz-2d

IOS quartz bubble with triangle


have some trouble getting quartz to draw the shape I want. Basically I am going for a shape like so:

bubble view

I can get the rounded bubble, but when I try to add in the triangle it goes wrong. Here is what I normally get:

enter image description here

Thanks for your time.

CGContextRef context = UIGraphicsGetCurrentContext();
CGRect currentFrame = self.bounds;

CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, self.BorderWidth);
CGContextSetStrokeColorWithColor(context, self.BorderColor.CGColor); 
CGContextSetFillColorWithColor(context, self.FillColor.CGColor);


float pad = BorderWidth + 0.5f;
float width = currentFrame.size.width - BorderWidth - 0.5f;
float height = currentFrame.size.height - BorderWidth - 0.5f;
float rounding = BorderRadius - BorderWidth;

CGContextMoveToPoint(context,pad + TriangleSize.width, pad);

//top
CGContextAddArcToPoint(context, 
                       width, 
                       pad, 
                       width, 
                       height, 
                       rounding);
//right
CGContextAddArcToPoint(context, 
                       width, 
                       height, 
                       round(width / 2.0f), 
                       height, 
                       rounding);
//bottom
CGContextAddArcToPoint(context, 
                       TriangleSize.width + pad, 
                       height, 
                       pad, 
                       pad , 
                       rounding);

//left
CGContextAddArcToPoint(context, 
                       TriangleSize.width, 
                       pad + TriangleSize.height*3, 
                       width, 
                       pad, 
                       0);

CGContextAddLineToPoint(context,-TriangleSize.width - pad,TriangleSize.height);
CGContextAddLineToPoint(context,pad + TriangleSize.width, pad + TriangleSize.height);

CGContextAddArcToPoint(context, 
                       pad + TriangleSize.width, 
                       pad - TriangleSize.height, 
                       width, 
                       height, 
                       rounding);

CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);

Solution

  • Looks like all I needed to do was post an question to figure it out. :) Anyway here is the code I used to get it working if anyone finds this later down the road:

     CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect currentFrame = self.bounds;
    
    CGContextSetLineJoin(context, kCGLineJoinRound);
    CGContextSetLineWidth(context, self.BorderWidth);
    CGContextSetStrokeColorWithColor(context, self.BorderColor.CGColor); 
    CGContextSetFillColorWithColor(context, self.FillColor.CGColor);
    
    
    float pad = BorderWidth + 0.5f;
    float width = currentFrame.size.width - BorderWidth - 0.5f;
    float height = currentFrame.size.height - BorderWidth - 0.5f;
    float rounding = BorderRadius - BorderWidth;
    float pos = (height/3); //height/2 //setting this to a third as I want the arrow to be a bit higher than the middle
    
    CGContextMoveToPoint(context,pad*3 + TriangleSize.width, pad);
    //top
    CGContextAddArcToPoint(context, 
                           width, 
                           pad, 
                           width, 
                           height, 
                           rounding);
    //right
    CGContextAddArcToPoint(context, 
                           width, 
                           height, 
                           round(width / 2.0f), 
                           height, 
                           rounding);
    //bottom
    CGContextAddArcToPoint(context, 
                           pad + TriangleSize.width,
                           height, 
                           pad, 
                           pad , 
                           rounding);
    
    CGContextAddLineToPoint(context, TriangleSize.width,pos + TriangleSize.height);
    CGContextAddLineToPoint(context, 0,pos);
    CGContextAddLineToPoint(context, TriangleSize.width,pos - TriangleSize.height);
    //left
    CGContextAddArcToPoint(context, 
                           pad + TriangleSize.width,
                           pad,
                           width, 
                           pad, 
                           rounding);
    
    
    CGContextClosePath(context);
    CGContextDrawPath(context, kCGPathFillStroke);
    
    // Draw a clipping path for the fill
    CGContextBeginPath(context);
    CGContextMoveToPoint(context,pad*3 + TriangleSize.width, pad);
    CGContextAddArcToPoint(context, width, pad, width, height, rounding);
    CGContextAddArcToPoint(context, width, height, round(width / 2.0f), height,rounding);
    CGContextAddArcToPoint(context, pad + TriangleSize.width,height, pad, pad, rounding);
    CGContextAddLineToPoint(context, TriangleSize.width,pos + TriangleSize.height);
    CGContextAddLineToPoint(context, 0,pos);
    CGContextAddLineToPoint(context, TriangleSize.width,pos - TriangleSize.height);
    CGContextAddArcToPoint(context, pad + TriangleSize.width,pad,width, pad, rounding);
    
    CGContextClosePath(context);
    CGContextClip(context);