drawInRect:withFont:lineBreakMode:alignment:' is deprecated - ios7

[[Util prettyDuration:self.mapBuilding.pendingBuild.secondsRemaining] drawInRect:CGRectMake(5.0, 0.0, 90.0, 15.0) withFont:TIME_FONT lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentRight];
[[Util prettyDuration:self.mapBuilding.work.secondsRemaining] drawInRect:CGRectMake(5.0, 20.0, 90.0, 15.0) withFont:TIME_FONT lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentRight];
[[self.mapBuilding.level stringValue] drawInRect:CGRectMake(30.0, 40.0, 40.0, 20.0) withFont:LEVEL_FONT lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentCenter];
In this code I am getting the below warning in iOS 8:
drawInRect:withFont:lineBreakMode:alignment:' is deprecated: first
deprecated in iOS 7.0 - Use -drawInRect:withAttributes:
How do I remove these warnings? I suspect the solution is the same for all 3 of them but not entirely sure.
Thanks

Related

iOS: Text get upside down in drawRect function

I am using PDFKit and create a subclass of PDFAnnotation, I want to set my custom padding when I create a free text annotation, so I try to override drawRect function as below
- (void)drawWithBox:(PDFDisplayBox)box inContext:(CGContextRef)context {
UIGraphicsPushContext(context);
CGContextSaveGState(context);
NSAttributedString * mystring = [[NSAttributedString alloc] initWithString:self.contents attributes:#{
NSFontAttributeName: self.font,
NSForegroundColorAttributeName: UIColor.blackColor }];
[mystring drawInRect:CGRectMake(self.bounds.origin.x + 10, self.bounds.origin.y + 10, self.bounds.size.width-20, self.bounds.size.height-20)];
CGContextRestoreGState(context);
UIGraphicsPopContext();
}
The padding works well but the text is upside down.
I try to add the context flipping code based on this link https://forums.developer.apple.com/thread/103683
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
after the line CGContextSaveGState(context);
But it will make the text disappear! Anyone know the reason or meet the similar issue? Thanks!
I have found the answer, in case someone meets the same problem. Actually the CGContextTransform are based on the page coordinate system, so when you use transform CGContextScaleCTM(context, 1.0, -1.0); the context is outside the page range. What we need to get is X1 = X2; Y1 + Y2 = 2 * (self.bounds.origin.y + self.bounds.size.height / 2), so apply transform CGContextConcatCTM(context, CGAffineTransformMake(1, 0, 0, -1, 0.0, 2 * self.bounds.origin.y + self.bounds.size.height)); works for me.

iOS 4.3 PDF file rendering issue

I use the following code to draw and rotate a PDF file. It works perfectly fine with iOS 5.x, but under iOS 4.3 just a white page shows up with an error in the debugger:
invalid `Contents': not an array of streams.
The error takes place right after "CGContextDrawPDFPage(context, pdfPage);"
Why does it work with iOS 5.x but does not 4.3.x? I tried different PDF files, but still I got the same result.
How do I overcome this issue?
pdfpage is defined as:
- (void)setPage:(CGPDFPageRef)newPage
{
CGPDFPageRelease(self->pdfPage);
self->pdfPage = CGPDFPageRetain(newPage);
}
the method where it happens:
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
// First fill the background with white.
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,self.bounds);
CGContextSaveGState(context);
int rotate = CGPDFPageGetRotationAngle(pdfPage);
switch (rotate) {
case 0:
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
break;
case 90:
CGContextScaleCTM(context, 1.0, -1.0);
CGContextRotateCTM(context, -M_PI / 2);
break;
case 180:
case -180:
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, self.bounds.size.width, 0);
CGContextRotateCTM(context, M_PI);
break;
case 270:
case -90:
CGContextTranslateCTM(context, self.bounds.size.height, self.bounds.size.width);
CGContextRotateCTM(context, M_PI / 2);
CGContextScaleCTM(context, -1, 1);
break;
}
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextScaleCTM(context, myScale,myScale);
CGContextDrawPDFPage(context, pdfPage); // the error shows up right after executing this line
CGContextRestoreGState(context);
}
According to PDF specification, the /Contents entry in the page dictionary can be either a stream object or an array of stream objects. Based on the error message, it seems the iOS 4.3 does not properly implement the PDF specification, it always expects an array of streams for the /Contents entry and your files use a single stream object. iOS 5 probably fixed this problem.
Try to do CGPDFDocumentRetain(yourCGPDFDocumentRef) at first.

why gradient colors and aliasing under Lion are different compare to Snow Leopard?

Just came across one weird problem. I generate programmatically a gradient inside round cornered square like so:
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceAdobeRGB1998);
CGContextRef mcontext = [[NSGraphicsContext currentContext] graphicsPort];
size_t capacityBarGradientNumLocations = 11;
CGGradientRef Gradient;
CGFloat capacityBarGradientLocations[11] = { /* skipped */ };
CGFloat capacityBarGradientColors[44] = { /* skipped */ };
Gradient = CGGradientCreateWithColorComponents (colorSpace, capacityBarGradientColors, capacityBarGradientLocations, capacityBarGradientNumLocations);
CGContextDrawLinearGradient(mcontext,Gradient, CGPointMake(0,baroffset), CGPointMake(0,barheight+baroffset), 0);
I've just noticed that the same code produces completely different results between Lion and Snow Leopard on the same mac (I have a dual boot) and monitor with the same color profiles. Please take a look at the screenshot:
Left part if taken under Lion, the right one - under Snow Leopard. How can I fix my gradient appearance under Lion?
Some extra info regarding the above picture. I've used a black color with variable alpha to generate semi transparent gradient i.e:
CGFloat capacityBarGradientColors[44] =
{ 0.0, 0.0, 0.0, .65,
0.0, 0.0, 0.0, .35,
/* skipped */
0.0, 0.0, 0.0, .35,
0.0, 0.0, 0.0, .65,
};
I thought maybe there is something wrong with the way i use alpha. Decided to use actual colors with Multiply blending mode and alpha set to 1.0 :
CGFloat capacityBarGradientColors[44] =
{ 0x59/255., 0x59/255., 0x59/255., 1.0,
0xa6/255., 0xa6/255., 0xa6/255., 1.0,
/* skipped */
0xa6/255., 0xa6/255., 0xa6/255., 1.0,
0x59/255., 0x59/255., 0x59/255., 1.0,
};
Under Snow Leopard I've got the result I've been looking for. But under Lion I've got completely different picture. take a look at the screenshot:
Left - Lion, right - Snow Leopard
Here is the code changes I did:
Gradient = CGGradientCreateWithColorComponents (colorSpace, capacityBarGradientColors, capacityBarGradientLocations, capacityBarGradientNumLocations);
CGContextSetBlendMode(mcontext, kCGBlendModeMultiply);
CGContextDrawLinearGradient(mcontext,Gradient, CGPointMake(0,baroffset), CGPointMake(0,barheight+baroffset), 0);
CGContextSetBlendMode(mcontext, kCGBlendModeNormal);
Could be something to do with the color space behaving differently (gamma?) from one OS version to the other. Do you have the same problem if you use kCGColorSpaceGenericRGB or kCGColorSpaceGenericRGBLinear?

A dynamic calendar Tab bar icon that changes to the actual date

Is there a way to make one as i have seen one on the istudiez pro app and was wondering how you would do it. This is what I have so far but the text test is not displayed. Not sure why?
#implementation TabBarIcon
CGContextRef CGBitmapContextCreate (
void *data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef colorspace,
CGBitmapInfo bitmapInfo
);
-(void)drawRect:(CGRect)Rect{
CGImageRef context = UIGraphicsGetCurrentContext();
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSelectFont(context, "Arial", 12.0, kCGEncodingMacRoman);
CGAffineTransform transform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, transform);
CGContextShowTextAtPoint(context, 100.0, 100.0, "test", strlen("test"));
}
CGImageRef CGBitmapContextCreateImage(CGContextRef context);
#end
Thanks
I'm not familiar with istudiez pro, but it sounds like it's just a matter of assigning a different tab bar image depending on the date; you haven't mentioned whether you're targeting iOS or OSX, but for the former you create an instance of UITabBarItem created with the appropriate image and assign it to the appropriate UIViewController's tabBarItem.
If it's just "day of the month" you could include all 31 possible images, otherwise you can use Core Graphics to draw the appropriate image at runtime.

CoreGraphics drawing on a large UIImage

I have a UIImage I draw lines on it that follow the users finger. It's like a drawing board. This works perfectly when the UIImage is small, say 500 x 600, but if it's like 1600 x 1200, it gets really scratchy and laggy. Is there a way I can optimize this? This is my drawing code in touchesModed:
UIGraphicsBeginImageContext(self.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 15.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
//CGContextSetAlpha(UIGraphicsGetCurrentContext(), 0.5f);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Thanks.
Instead of drawing the entire 1600X1200 frame at a single go, why not draw it as it's needed. What I mean is since you are drawing the entire frame (which resides in memory) you are having patchy performance.
Try CATiledLayer. Basically you need to draw a screen size only which your device is capable of, anything more than that as the user scrolls you need to draw it on the fly.
This is what is used in Google Maps on iPad or iPhone. Hope this helps...
Instead of creating a new context and drawing the current image into it every time a touch moves, create a context using CGBitmapContextCreate and reuse that context. All previous drawing will already be in the context, and you won't have to create a new context each time a touch moves.
- (CGContextRef)drawingContext {
if(!context) { // context is an instance variable of type CGContextRef
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if(!colorSpace) return nil;
context = CGBitmapContextCreate(NULL, contextSize.width, contextSize.height,
8, contextSize.width * 32, colorSpace,
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
if(!context) return nil;
CGContextConcatCTM(context, CGAffineTransformMake(1,0,0,-1,0,contextSize.height));
CGContextDrawImage(context, (CGRect){CGPointZero,contextSize}, drawImageView.image.CGImage);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 15.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
}
return context;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGContextRef ctxt = [self drawingContext];
CGContextBeginPath(ctxt);
CGContextMoveToPoint(ctxt, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(ctxt, currentPoint.x, currentPoint.y);
CGContextStrokePath(ctxt);
CGImageRef img = CGBitmapContextCreateImage(ctxt);
drawImageView.image = [UIImage imageWithCGImage:img];
CGImageRelease(img);
}
This code requires the instance variables CGContextRef context and CGSize contextSize. The context will need to be released in dealloc, and whenever you change its size.