drawWithFrame NSOutlineView Flickr - objective-c

I have a custom cell class for NSOutlineView
In the cell class I have implemented the drawWithFrame.
The rect provided(cellFrame) I divide into 3 parts
(a) Image
(b) Text
(c) Darwing (ellipse/circle / rectangle)
The image is drawn using [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
The ellipse is drawn using [[NSBezierPath bezierPathWithRoundedRect:ellipseRect xRadius:10 yRadius:10] fill];
The text rect is given to the super class to draw the text
[super drawInteriorWithFrame:newFrame inView:controlView];
Now my problem is that when any cell of the outline view expands, all the drawing (ellipse etc) flickr and appear to be redrawn, even if the cell was not expanded.
Can anyone help me to resolve this..
Here is the code
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
//cellFrame.size.height -=16;
Option *ol = [self representedObject];
uint64_t sz;
int fontSize=10;
NSString *sizeText;
MyFile *tmpf;
//NSImage *image = [ol getImage];
if (image != nil)
{
// the cell has an image: draw the normal item cell
NSSize imageSize;
NSRect imageFrame;
imageSize = [image size];
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
imageFrame.origin.x += kImageOriginXOffset;
imageFrame.origin.y -= kImageOriginYOffset;
imageFrame.size = NSMakeSize(12,12);
if ([controlView isFlipped])
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
else
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
imageFrame.origin.y+=18;
imageFrame.size.width = cellFrame.size.width - 18;
imageFrame.origin.x+=18;
sz = [ol getsize];
/////////////////////////////////
NSRect newFrame = cellFrame;
newFrame.origin.x += kTextOriginXOffset;
newFrame.origin.y += kTextOriginYOffset;
newFrame.size.height -= kTextHeightAdjust;
newFrame.size.width -= 65;
if(sz)
{
//newFrame.origin.x += 65;
NSRect tmpframe = newFrame;
NSRect ellipseRect = NSMakeRect(tmpframe.origin.x+tmpframe.size.width+1,
tmpframe.origin.y+ kTextOriginYOffset,
60,16);
//////// ****ALLOC ********
tmpf = [[MyFile alloc] init];
[tmpf setfsize:sz];
sizeText = [tmpf getFormattedfize];
// [NSShadow setShadowWithOffset:NSMakeSize(0, -8 * 1) blurRadius:12 * 1
// color:[NSColor colorWithCalibratedWhite:0 alpha:0.75]];
[[NSColor colorWithCalibratedWhite:0.9 alpha:1.0] set];
[[NSBezierPath bezierPathWithRoundedRect:ellipseRect xRadius:10 yRadius:10] fill];
// [NSShadow clearShadow];
TextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSColor textColor],
NSForegroundColorAttributeName,
[NSFont systemFontOfSize:10],
NSFontAttributeName, nil];
[sizeText drawAtPoint:NSMakePoint(ellipseRect.origin.x+3, ellipseRect.origin.y+2)
withAttributes:TextAttributes];
//////// ****RELEASE *******
[tmpf release];
}
[super drawInteriorWithFrame:newFrame inView:controlView];
}
}

Related

Make BG of macOS screensaver black?

I'm new to Obj-C so apologies if my code is messy.
I've made a screensaver of a DVD logo that changes colour on each bounce. My only problem is the background--it's dark grey instead of black. I'm hoping somebody could help me out.
Here is some of my code:
NSString * dvdPath = [[NSBundle bundleForClass:[self class]] pathForResource:#"dvdlogo" ofType:#"png"];
self.dvdLogo = [[NSImage alloc] initWithContentsOfFile:dvdPath];[self hitWall];}return self;}
- (void)startAnimation
{[super startAnimation];}
- (void)stopAnimation
{[super stopAnimation];}
- (void)drawRect:(NSRect)rectParam
{const float g = 15.0f/255.0f;
[[NSColor colorWithRed:g green:g blue:g alpha:1] setFill];
NSRectFill(rectParam);
NSRect rect;
rect.size = NSMakeSize(self.dvdWidth, self.dvdHeight);
self.x += self.xSpeed;
self.y += self.ySpeed;
rect.origin = CGPointMake(self.x, self.y);
self.dirtyRect = rect;
[self.dvdLogo drawInRect:rect];
CGPoint centre = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
if (centre.x + self.dvdWidth / 2 >= WIDTH || centre.x - self.dvdWidth / 2 <= 0) {
self.xSpeed *= -1;
[self hitWall];}
if (centre.y + self.dvdHeight / 2 >= HEIGHT || centre.y - self.dvdHeight / 2 <= 0) {
self.ySpeed *= -1;
[self hitWall];}}
- (void)hitWall
{NSArray * colours = #[[NSColor redColor],
[NSColor blueColor],
[NSColor yellowColor],
[NSColor cyanColor],
[NSColor orangeColor],
[NSColor magentaColor],
[NSColor greenColor]];
self.dvdColor = colours[arc4random() % [colours count]];
[self.dvdLogo lockFocus];
[self.dvdColor set];
NSRect imageRect = {NSZeroPoint, [self.dvdLogo size]};
NSRectFillUsingOperation(imageRect, NSCompositingOperationSourceAtop);
[self.dvdLogo unlockFocus];}
- (void)animateOneFrame
{//[self setNeedsDisplay:true];
[self setNeedsDisplayInRect:self.dirtyRect];
return;}
Here's a download of the saver, if you wanna see what I'm talking about.
If I follow your code fragment and problem correctly your drawRect starts with:
const float g = 15.0f/255.0f;
[[NSColor colorWithRed:g green:g blue:g alpha:1] setFill];
NSRectFill(rectParam);
This fills the area defined by rectParam with dark gray. Why did you choose 15.0f/255.0f for the RGB components? Black is just 0 but more easily obtained using blackColor:
[[NSColor blackColor] setFill];
HTH

Drawing leaves trails when resizing window

I am trying to draw a box in custom view. I have the points for the corners of the box and they are scaled. If I put a small rectangle at each vertex on the box and the resize the window it works perfectly. If I use [path stroke] to draw the lines between the vertices and then resize the window, I end up with a mess as the box is redrawn as the window gets resized, so instead of a single box in a resized window I get all the boxes that were redrawn. I have not found a way to clear the custom view of all the intermediary drawings. Any help would be appreciated. Also, I am really new at this.
#import <Cocoa/Cocoa.h>
#interface PointDisplay : NSView
{
NSBezierPath *pathForLine;
NSMutableArray *pointList;
float originalWidth;
float originalHeight;
}
#end
import "PointDisplay.h"
#implementation PointDisplay
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self)
{
int opts = (NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved);
NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:area];
pathForLine = [[NSBezierPath alloc] init];
pointList = [[NSMutableArray alloc] init];
NSRect originalRect = [self bounds];
originalWidth = originalRect.size.width;
originalHeight = originalRect.size.height;
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
NSRect myRect = [self bounds];
float widthNow = myRect.size.width;
float heightNow = myRect.size.height;
[[NSColor greenColor] set];
[NSBezierPath fillRect:myRect];
int rectWidth = 10, rectHeight = 10;
float lineWidth = 3.0;
if (pointList.count != 0)
{
NSPoint myPoint = [pointList[0] locationInWindow];
myPoint = [self convertPoint:myPoint fromView:nil];
myPoint.x = (myPoint.x - rectWidth / 2) * widthNow / originalWidth;
myPoint.y = (myPoint.y - rectHeight / 2) * heightNow / originalHeight;
[pathForLine moveToPoint:myPoint];
NSRect anotherRect = NSMakeRect(myPoint.x, myPoint.y, rectWidth, rectHeight);
[[NSColor redColor] set];
[pathForLine setLineWidth:lineWidth + .5 * ((int)lineWidth % 2)];
//[[NSBezierPath bezierPathWithRect:anotherRect] stroke];
for (int i = 1; i < pointList.count; i++)
{
myPoint = [pointList[i] locationInWindow];
myPoint = [self convertPoint:myPoint fromView:nil];
myPoint.x = (myPoint.x - 5) * widthNow / originalWidth;
myPoint.y = (myPoint.y - 5) * heightNow / originalHeight;
anotherRect = NSMakeRect(myPoint.x, myPoint.y, 10, 10);
[pathForLine lineToPoint:myPoint];
[pathForLine stroke];
//[[NSBezierPath bezierPathWithRect:anotherRect] fill];
}
}
}
#pragma mark Mouse events
- (void)mouseUp:(NSEvent *)theEvent
{
[pointList addObject:theEvent];
[self setNeedsDisplay:YES];
}
- (void)mouseExited:(NSEvent *)theEvent
{
[pathForLine closePath];
[pathForLine stroke];
[self setNeedsDisplay:YES];
}
#end

Stripped stroke on NSBezierPath

I am trying to draw a simple diagram. I have squares that are connected by lines. The lines are drawn with NSBezierPath's. I am using a random color for the lines so I can follow them. My problem is that the lines change color.
The output -
Code - I removed the lines that draw the squares so it only draws the lines:
- (void)drawRect:(NSRect)dirtyRect
{
// Drawing code here.
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
CGFloat height = 70.0f;
CGFloat yOffset = 20.0f;
NSRect rect = NSMakeRect(50.0f, 50.0f, 200.0f, height);
NSEnumerator *reverseEnumerator = [steps reverseObjectEnumerator];
NSMutableDictionary *rectsByStep = [NSMutableDictionary dictionaryWithCapacity:10];
for( WFGJobStep *step in reverseEnumerator )
{
[[NSColor redColor] setFill];
[rectsByStep setObject:[NSValue valueWithRect:rect] forKey:[NSNumber numberWithInteger:step.step]];
rect.origin.y += height + yOffset;
}
reverseEnumerator = [steps reverseObjectEnumerator];
for( WFGJobStep *step in reverseEnumerator )
{
NSRect stepRect = [[rectsByStep objectForKey:[NSNumber numberWithInteger:step.step]] rectValue];
NSPoint startPoint = NSMakePoint( stepRect.origin.x + stepRect.size.width, stepRect.origin.y);
// draw lines
for( NSNumber *stepNumber in step.nextSteps )
{
//
//
// Line drawing code here
//
//
NSBezierPath * path = [NSBezierPath bezierPath];
[path setLineWidth: 4];
NSRect targetStepRect = [[rectsByStep objectForKey:stepNumber] rectValue];
NSPoint endPoint = NSMakePoint( targetStepRect.origin.x + targetStepRect.size.width, targetStepRect.origin.y + targetStepRect.size.height);
[path moveToPoint:startPoint];
CGFloat controlX = ( startPoint.y - endPoint.y ) * .2 + stepRect.origin.x + stepRect.size.width + 20;
[path curveToPoint:endPoint controlPoint1:NSMakePoint(controlX, startPoint.y) controlPoint2:NSMakePoint(controlX, endPoint.y)];
NSRect square = NSMakeRect( endPoint.x, endPoint.y, 9, 9 );
[path appendBezierPathWithOvalInRect: square];
[[self randomColor] set];
[path stroke];
}
}
}
- (NSColor *)randomColor {
float c[4];
c[0] = (arc4random() / RAND_MAX) * 1;
c[1] = (arc4random() / RAND_MAX) * 1;
c[2] = (arc4random() / RAND_MAX) * 1;
c[3] = 1.0f;
return [NSColor colorWithDeviceRed:c[0] green:c[1] blue:c[2] alpha:c[3]];
}
My issue is that this is in a scoll view and this is my first NSScrollView. I was not aware that as the view scrolls it redraws its subviews. The issue was that I was using a random color for my stroke so that as I scrolled it would randomly change the colors of the lines.

Display NSImage on a CALayer

I've been trying to display a NSImage on a CALayer. Then I realised I need to convert it to a CGImage apparently, then display it...
I have this code which doesn't seem to be working
CALayer *layer = [CALayer layer];
NSImage *finderIcon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFinderIcon)];
[finderIcon setSize:(NSSize){ 128.0f, 128.0f }];
CGImageSourceRef source;
source = CGImageSourceCreateWithData((CFDataRef)finderIcon, NULL);
CGImageRef finalIcon = CGImageSourceCreateImageAtIndex(source, 0, NULL);
layer.bounds = CGRectMake(128.0f, 128.0f, 4, 4);
layer.position = CGPointMake(128.0f, 128.0f);
layer.contents = finalIcon;
// Insert the layer into the root layer
[mainLayer addSublayer:layer];
Why? How can I get this to work?
From the comments: Actually, if you're on 10.6, you can also just set the CALayer's contents to an NSImage rather than a CGImageRef...
If you're on OS X 10.6 or later, take a look at NSImage's CGImageForProposedRect:context:hints: method.
If you're not, I've got this in a category on NSImage:
-(CGImageRef)CGImage
{
CGContextRef bitmapCtx = CGBitmapContextCreate(NULL/*data - pass NULL to let CG allocate the memory*/,
[self size].width,
[self size].height,
8 /*bitsPerComponent*/,
0 /*bytesPerRow - CG will calculate it for you if it's allocating the data. This might get padded out a bit for better alignment*/,
[[NSColorSpace genericRGBColorSpace] CGColorSpace],
kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedFirst);
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bitmapCtx flipped:NO]];
[self drawInRect:NSMakeRect(0,0, [self size].width, [self size].height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapCtx);
CGContextRelease(bitmapCtx);
return (CGImageRef)[(id)cgImage autorelease];
}
I think I wrote this myself. But it's entirely possible that I ripped it off from somewhere else like Stack Overflow. It's an older personal project and I don't really remember.
Here's some code which may help you - I sure hope the formatting of this does not get all messed up like it appears is going to happen - all I can offer is that this works for me.
// -------------------------------------------------------------------------------------
- (void)awakeFromNib
{
// setup our main window 'contentWindow' to use layers
[[contentWindow contentView] setWantsLayer:YES]; // NSWindow*
// create a root layer to contain all of our layers
CALayer *root = [[contentWindow contentView] layer];
// use constraint layout to allow sublayers to center themselves
root.layoutManager = [CAConstraintLayoutManager layoutManager];
// create a new layer which will contain ALL our sublayers
// -------------------------------------------------------
mContainer = [CALayer layer];
mContainer.bounds = root.bounds;
mContainer.frame = root.frame;
mContainer.position = CGPointMake(root.bounds.size.width * 0.5,
root.bounds.size.height * 0.5);
// insert layer on the bottom of the stack so it is behind the controls
[root insertSublayer:mContainer atIndex:0];
// make it resize when its superlayer does
root.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
// make it resize when its superlayer does
mContainer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
}
// -------------------------------------------------------------------------------------
- (void) loadMyImage:(NSString*) path
n:(NSInteger) num
x:(NSInteger) xpos
y:(NSInteger) ypos
h:(NSInteger) hgt
w:(NSInteger) wid
b:(NSString*) blendstr
{
#ifdef __DEBUG_LOGGING__
NSLog(#"loadMyImage - ENTER [%#] num[%d] x[%d] y[%d] h[%d] w[%d] b[%#]",
path, num, xpos, ypos, hgt, wid, blendstr);
#endif
NSInteger xoffset = ((wid / 2) + xpos); // use CORNER versus CENTER for location
NSInteger yoffset = ((hgt / 2) + ypos);
CIFilter* filter = nil;
CGRect cgrect = CGRectMake((CGFloat) xoffset, (CGFloat) yoffset,
(CGFloat) wid, (CGFloat) hgt);
if(nil != blendstr) // would be equivalent to #"CIMultiplyBlendMode" or similar
{
filter = [CIFilter filterWithName:blendstr];
}
// read image file via supplied path
NSImage* theimage = [[NSImage alloc] initWithContentsOfFile:path];
if(nil != theimage)
{
[self setMyImageLayer:[CALayer layer]]; // create layer
myImageLayer.frame = cgrect; // locate & size image
myImageLayer.compositingFilter = filter; // nil is OK if no filter
[myImageLayer setContents:(id) theimage]; // deposit image into layer
// add new layer into our main layer [see awakeFromNib above]
[mContainer insertSublayer:myImageLayer atIndex:0];
[theimage release];
}
else
{
NSLog(#"ERROR loadMyImage - no such image [%#]", path);
}
}
+ (CGImageRef) getCachedImage:(NSString *) imageName
{
NSGraphicsContext *context = [[NSGraphicsContext currentContext] graphicsPort];
NSImage *img = [NSImage imageNamed:imageName];
NSRect rect = NSMakeRect(0, 0, [img size].width, [img size].height);
return [img CGImageForProposedRect:&rect context:context hints:NULL];
}
+ (CGImageRef) getImage:(NSString *) imageName withExtension:(NSString *) extension
{
NSGraphicsContext *context = [[NSGraphicsContext currentContext] graphicsPort];
NSString* imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:extension];
NSImage* img = [[NSImage alloc] initWithContentsOfFile:imagePath];
NSRect rect = NSMakeRect(0, 0, [img size].width, [img size].height);
CGImageRef imgRef = [img CGImageForProposedRect:&rect context:context hints:NULL];
[img release];
return imgRef;
}
then you can set it:
yourLayer.contents = (id)[self getCachedImage:#"myImage.png"];
or
yourLayer.contents = (id)[self getImage:#"myImage" withExtension:#"png"];

How to use NSString drawInRect to center text?

How can I draw a NSString centered within a NSRect?
I've started off with: (an extract from the drawRect method of my custom view)
NSString* theString = ...
[theString drawInRect:theRect withAttributes:0];
[theString release];
Now I'm assuming I need to set up some attributes. I've had a look through Apple's Cocoa documentation, but it's a bit overwhelming and can't find anything for how to add paragraph styles to the attributes.
Also, I can only find horizontal alignment, what about vertical alignment?
Vertical alignment you'll have to do yourself ((height of view + height of string)/2). Horizontal alignment you can do with:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentCenter;
NSDictionary *attr = [NSDictionary dictionaryWithObject:style forKey:NSParagraphStyleAttributeName];
[myString drawInRect:someRect withAttributes:attr];
This works for me for horizontal alignment
[textX drawInRect:theRect
withFont:font
lineBreakMode:UILineBreakModeClip
alignment:UITextAlignmentCenter];
Martins answer is pretty close, but it has a few small errors. Try this:
NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *attr =
[NSDictionary dictionaryWithObject:style
forKey:NSParagraphStyleAttributeName];
[myString drawInRect:someRect withAttributes:attr];
[style release];
You'll have to create a new NSMutableParagraphStyle (instead of using the default paragraph style as Martin suggested) because [NSMutableParagraphStyle defaultParagraphStyle] returns an NSParagraphStyle, which doesn't have the setAlignment method. Also, you don't need the string #"NSParagraphStyleAttributeName"—just NSParagraphStyleAttributeName.
This works for me:
CGRect viewRect = CGRectMake(x, y, w, h);
UIFont* font = [UIFont systemFontOfSize:15];
CGSize size = [nsText sizeWithFont:font
constrainedToSize:viewRect.size
lineBreakMode:(UILineBreakModeWordWrap)];
float x_pos = (viewRect.size.width - size.width) / 2;
float y_pos = (viewRect.size.height - size.height) /2;
[someText drawAtPoint:CGPointMake(viewRect.origin.x + x_pos, viewRect.origin.y + y_pos) withFont:font];
[NSMutableParagraphStyle defaultParagraphStyle] won't work use:
[NSMutableParagraphStyle new]
also, it appears horizontal alignment only works for drawInRect, not drawAtPoint (ask me how I know :-)
For anyone interested in an iOS7+ adaptation, drop this in an NSString category:
- (void)drawVerticallyInRect:(CGRect)rect withFont:(UIFont *)font color:(UIColor *)color andAlignment:(NSTextAlignment)alignment
{
rect.origin.y = rect.origin.y + ((rect.size.height - [self sizeWithAttributes:#{NSFontAttributeName:font}].height) / 2);
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:alignment];
[self drawInRect:rect withAttributes:#{
NSFontAttributeName : font,
NSForegroundColorAttributeName : color,
NSParagraphStyleAttributeName : style
}];
}
For iOS Swift,
To center String within the rectangle using the method draw(in:withAttributes:)
func drawInCenter(_ text: String, into rectangle: CGRect, with textFont: UIFont) {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let rectangle = CGRect.zero
paragraphStyle.minimumLineHeight = rectangle.height / 2 + textFont.lineHeight / 2
let textAttributes = [NSAttributedString.Key.font: textFont,
NSAttributedString.Key.paragraphStyle: paragraphStyle] as [NSAttributedString.Key : Any]
(text as NSString).draw(in: rectangle, withAttributes: textAttributes)
}
Well, drawInRect is only good for basic text drawing (in other words, the system decides where to position your text) - often the only way to draw text positioned where you want is to simply calculate what point you want it at and use NSString's drawAtPoint:withAttributes:.
Also, NSString's sizeWithAttributes is hugely useful in any positioning math you end up having to do for drawAtPoint.
Good luck!
The correct answer is:
-drawInRect:withFont:lineBreakMode:alignment:
I also created a small category for vertical alignment. If you like to use it, go ahead :)
// NSString+NSVerticalAlign.h
typedef enum {
NSVerticalTextAlignmentTop,
NSVerticalTextAlignmentMiddle,
NSVerticalTextAlignmentBottom
} NSVerticalTextAlignment;
#interface NSString (VerticalAlign)
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font verticalAlignment:(NSVerticalTextAlignment)vAlign;
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode verticalAlignment:(NSVerticalTextAlignment)vAlign;
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode alignment:(NSTextAlignment)alignment verticalAlignment:(NSVerticalTextAlignment)vAlign;
#end
// NSString+NSVerticalAlign.m
#import "NSString+NSVerticalAlign.h"
#implementation NSString (VerticalAlign)
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font];
}
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font lineBreakMode:lineBreakMode];
}
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode alignment:(NSTextAlignment)alignment verticalAlignment:(NSVerticalTextAlignment)vAlign {
switch (vAlign) {
case NSVerticalTextAlignmentTop:
break;
case NSVerticalTextAlignmentMiddle:
rect.origin.y = rect.origin.y + ((rect.size.height - font.pointSize) / 2);
break;
case NSVerticalTextAlignmentBottom:
rect.origin.y = rect.origin.y + rect.size.height - font.pointSize;
break;
}
return [self drawInRect:rect withFont:font lineBreakMode:lineBreakMode alignment:alignment];
}
#end
The following snippet is useful for drawing a center text string using an Annotation custom image as a reference:
CustomAnnotation.h
#interface CustomAnnotation : MKAnnotationView
[...]
CustomAnnotation.m
[...]
- (void)drawRect:(CGRect)rect
{
ClusterAnnotation *associatedAnnotation = (CustomAnnotation *)self.annotation;
if (associatedAnnotation != nil)
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSString *imageName = #"custom_image.png";
CGRect contextRect = CGRectMake(0, 0, 42.0, 42.0);
CGFloat fontSize = 14.0;
[[UIImage imageNamed:imageName] drawInRect:contextRect];
NSInteger myIntegerValue = [associatedAnnotation.dataObject.myIntegerValue integerValue];
NSString *myStringText = [NSString stringWithFormat:#"%d", myIntegerValue];
UIFont *font = [UIFont fontWithName:#"Helvetica-Bold" size:fontSize];
CGSize fontWidth = [myStringText sizeWithFont:font];
CGFloat yOffset = (contextRect.size.height - fontWidth.height) / 2.0;
CGFloat xOffset = (contextRect.size.width - fontWidth.width) / 2.0;
CGPoint textPoint = CGPointMake(contextRect.origin.x + xOffset, contextRect.origin.y + yOffset);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetLineWidth(context, fontSize/10);
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
[myStringText drawAtPoint:textPoint withFont:font];
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
[myStringText drawAtPoint:textPoint withFont:font];
}
}