I have no experience in Quartz drawing.
I need to draw a rectangle on callout view. i found some sample code to draw it.
My current code for that is
- (void)drawRect:(CGRect)rect {
CGFloat stroke = 1.0;
CGFloat radius = 7.0;
CGMutablePathRef path = CGPathCreateMutable();
UIColor *color;
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat parentX = [self relativeParentXPosition];
//Determine Size
rect = self.bounds;
rect.size.width -= stroke + 14;
rect.size.height -= stroke + 14 + CalloutMapAnnotationViewHeightAboveParent;
rect.origin.x += stroke / 2.0 + 7;
rect.origin.y += stroke / 2.0 + 7;
//Create Path For Callout Bubble
CGPathMoveToPoint(path, NULL, rect.origin.x, rect.origin.y + radius);
CGPathAddLineToPoint(path, NULL, rect.origin.x, rect.origin.y + rect.size.height - radius);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, 0.0f, M_PI / 2, 1);
CGPathAddLineToPoint(path, NULL, parentX - 15, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y + rect.size.height + 15);
CGPathAddLineToPoint(path, NULL, parentX + 15, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width, rect.origin.y + radius);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI / 2, 1);
CGPathAddLineToPoint(path, NULL, rect.origin.x + radius, rect.origin.y);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, M_PI, 1);
CGPathCloseSubpath(path);
//Fill Callout Bubble & Add Shadow
color = [[UIColor blackColor] colorWithAlphaComponent:.6];
[color setFill];
CGContextAddPath(context, path);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake (0, self.yShadowOffset), 6, [UIColor colorWithWhite:0 alpha:.5].CGColor);
CGContextFillPath(context);
CGContextRestoreGState(context);
//Stroke Callout Bubble
color = [[UIColor darkGrayColor] colorWithAlphaComponent:.9];
[color setStroke];
CGContextSetLineWidth(context, stroke);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextAddPath(context, path);
CGContextStrokePath(context);
//Determine Size for Gloss
CGRect glossRect = self.bounds;
glossRect.size.width = rect.size.width - stroke;
glossRect.size.height = (rect.size.height - stroke) / 2;
glossRect.origin.x = rect.origin.x + stroke / 2;
glossRect.origin.y += rect.origin.y + stroke / 2;
CGFloat glossTopRadius = radius - stroke / 2;
CGFloat glossBottomRadius = radius / 1.5;
//Create Path For Gloss
CGMutablePathRef glossPath = CGPathCreateMutable();
CGPathMoveToPoint(glossPath, NULL, glossRect.origin.x, glossRect.origin.y + glossTopRadius);
CGPathAddLineToPoint(glossPath, NULL, glossRect.origin.x, glossRect.origin.y + glossRect.size.height - glossBottomRadius);
CGPathAddArc(glossPath, NULL, glossRect.origin.x + glossBottomRadius, glossRect.origin.y + glossRect.size.height - glossBottomRadius, glossBottomRadius, M_PI, M_PI / 2, 1);
CGPathAddLineToPoint(glossPath, NULL, glossRect.origin.x + glossRect.size.width - glossBottomRadius, glossRect.origin.y + glossRect.size.height);
CGPathAddArc(glossPath, NULL, glossRect.origin.x + glossRect.size.width - glossBottomRadius, glossRect.origin.y + glossRect.size.height - glossBottomRadius, glossBottomRadius, M_PI / 2, 0.0f, 1);
CGPathAddLineToPoint(glossPath, NULL, glossRect.origin.x + glossRect.size.width, glossRect.origin.y + glossTopRadius);
CGPathAddArc(glossPath, NULL, glossRect.origin.x + glossRect.size.width - glossTopRadius, glossRect.origin.y + glossTopRadius, glossTopRadius, 0.0f, -M_PI / 2, 1);
CGPathAddLineToPoint(glossPath, NULL, glossRect.origin.x + glossTopRadius, glossRect.origin.y);
CGPathAddArc(glossPath, NULL, glossRect.origin.x + glossTopRadius, glossRect.origin.y + glossTopRadius, glossTopRadius, -M_PI / 2, M_PI, 1);
CGPathCloseSubpath(glossPath);
//Fill Gloss Path
CGContextAddPath(context, glossPath);
CGContextClip(context);
CGFloat colors[] =
{
1, 1, 1, .3,
1, 1, 1, .1,
};
CGFloat locations[] = { 0, 1.0 };
CGGradientRef gradient = CGGradientCreateWithColorComponents(space, colors, locations, 2);
CGPoint startPoint = glossRect.origin;
CGPoint endPoint = CGPointMake(glossRect.origin.x, glossRect.origin.y + glossRect.size.height);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
//Gradient Stroke Gloss Path
CGContextAddPath(context, glossPath);
CGContextSetLineWidth(context, 2);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
CGFloat colors2[] =
{
1, 1, 1, .3,
1, 1, 1, .1,
1, 1, 1, .0,
};
CGFloat locations2[] = { 0, .1, 1.0 };
CGGradientRef gradient2 = CGGradientCreateWithColorComponents(space, colors2, locations2, 3);
CGPoint startPoint2 = glossRect.origin;
CGPoint endPoint2 = CGPointMake(glossRect.origin.x, glossRect.origin.y + glossRect.size.height);
CGContextDrawLinearGradient(context, gradient2, startPoint2, endPoint2, 0);
//Cleanup
CGPathRelease(path);
CGPathRelease(glossPath);
CGColorSpaceRelease(space);
CGGradientRelease(gradient);
CGGradientRelease(gradient2);
}
this is the current callout i am getting.But i need to draw that triangle shape at the edge at the top of the rectangle.
by studding it these 2 two lines i need to change
CGPathAddLineToPoint(path, NULL, parentX - 15, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y + rect.size.height + 15);
but i am poor in quartz graphics.
my required callout is like below image
triangle need to up of the callout view.
people who have knowledge on quartz graphics please help me.
Well, if you're looking for the callout to be on the top, try this. Replace the path for the callout bubble with the following:
//Determine Size
rect = self.bounds;
rect.size.width -= stroke + 14;
rect.size.height -= stroke + 14 + CalloutMapAnnotationViewHeightAboveParent;
rect.origin.x += stroke / 2.0 + 7;
rect.origin.y += stroke / 2.0 + 7 + 14;
//Create Path For Callout Bubble
CGPathMoveToPoint(path, NULL, rect.origin.x, rect.origin.y + radius);
CGPathAddLineToPoint(path, NULL, rect.origin.x, rect.origin.y + rect.size.height - radius); //Left line
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, 0.0f, M_PI / 2, 1); //Bottom left arc
// CGPathAddLineToPoint(path, NULL, parentX - 15, rect.origin.y + rect.size.height); //bottom to callout line
// CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y + rect.size.height + 15); //callout left
// CGPathAddLineToPoint(path, NULL, parentX + 15, rect.origin.y + rect.size.height); //callout right
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height); //bottom to right line
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1); //bottom right
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width, rect.origin.y + radius); //right line
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI / 2, 1); //top right
CGPathAddLineToPoint(path, NULL, parentX + 15, rect.origin.y); //top right to right callout
CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y - 15); //callout right
CGPathAddLineToPoint(path, NULL, parentX - 15, rect.origin.y); //callout left
CGPathAddLineToPoint(path, NULL, rect.origin.x + radius, rect.origin.y); //top left callout to top left
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, M_PI, 1); //top left
CGPathCloseSubpath(path); //Path closed, no line draw
I believe this should work (haven't tested it). But the gloss path is dependent on that callout rect being used so I think everything else should work fine.
As a side note, Core Graphics involves drawing paths kind of like drawing on a piece of paper. A CGPathMoveToPoint involves putting the pencil down. Everything after that is drawing either lines or arcs sequentially. All you need to do is read the point that the line/curve is being drawn to. Note that arcs are translated into curves, but to read them you need to know where pi, pi/2 and pi/4 is on a unit circle. That tells you where the arc is being drawn. But in general, you can assume (at least in this case) that the arc is corresponding to the actual corner the previous line was drawn to. I added comments indicating what path elements correspond to what part of the box. I also commented out the bottom callout rather than delete it. You can uncomment it to draw the bottom callout again but you'll need to remember to comment out the top and shift the rect back up (I shifted it down by 14). Also consider avoiding using 'magic numbers', like the size of the callout (15) and instead put something like this in your file:
#define CalloutSize 15.0f
Doing this and inserting CalloutSize
into the code rather than 15
will allow you to easily change it's size without having to search for each instance it's being used.