How to add an UIActivityIndicator into a drawRect - ios

I want to know how could I add an activity indicator (in the middle of a HUD) to this drawrect method (i'm trying to create a hud with the activity on it)
- (void)drawRect:(CGRect)rect {
// Sets the rectangle to be 96 X 96.
const CGFloat boxWidth = 120.0f;
const CGFloat boxHeight = 120.0f;
// This method is used to calculate the position of the rectangle.
CGRect boxRect = CGRectMake( roundf(self.bounds.size.width - boxWidth) / 2.0f, roundf(self.bounds.size.height - boxHeight) / 2.0f, boxWidth,boxHeight);
// This draws the rectangle with rounded corners.
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:10.0f];
[[UIColor colorWithWhite:0.0f alpha:0.75] setFill];
[roundedRect fill];
[[UIColor whiteColor] set]; // Sets the color of the font to white.
UIFont *font = [UIFont boldSystemFontOfSize:16.0f]; // Sets the size of the font to 16.
CGSize textSize = [self.text sizeWithFont:font];
// Calculates where to draw the text.
CGPoint textPoint = CGPointMake( self.center.x - roundf(textSize.width / 2.0f), self.center.y - roundf(textSize.height / 2.0f) + boxHeight / 4.0f);
// Draws the text on the rectangle.
[self.text drawAtPoint:textPoint withFont:font];
}
Thanks!

You don't. Activity indicator is a type of view, so you'd add it as a subview of your HUD and it will draw itself.

Related

Draw and rotate Text along a stroke

I try to rotate a text along a stroke. The user can create strokes by touch and move the finger in an direction he wants, the stroke then scales to the point where the finger is. I want to show the current length along the stroke and the text show stay scale and rotate with the stroke.
I think im not so far away from the working solution. Currently the text is not always at the right position, its depends on the rotation. I think there is something wrong with Context Translation, but lets see my code.
This is my method to draw the text:
- (void)drawText:(NSString *)text withFrame:(CGRect)rect withFont:(UIFont *)font rotation:(float)radians alignment:(NSTextAlignment)alignment context:(CGContextRef)context {
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
paragraphStyle.alignment = alignment;
NSDictionary *attributes = #{ NSFontAttributeName: font,
NSParagraphStyleAttributeName: paragraphStyle,
NSForegroundColorAttributeName: [UIColor blackColor] };
CGContextSaveGState(context);
CGContextScaleCTM(context, 1.0, 1.0);
//CGRect textSize = [text boundingRectWithSize:rect.size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
CGContextTranslateCTM(context, rect.origin.x + (rect.size.width * 0.5), rect.origin.y + (rect.size.height * 0.5));
CGContextRotateCTM(context, radians);
CGContextTranslateCTM(context, -(rect.origin.x + (rect.size.width * 0.5)), -(rect.origin.y + (rect.size.height * 0.5)));
[[UIColor redColor] set];
CGContextFillRect(context, rect);
[text drawInRect:rect withAttributes:attributes];
CGContextRestoreGState(context);
}
I call it like this:
CGFloat a = shapeToBeDrawn.startPoint.y - shapeToBeDrawn.endPoint.y;
CGFloat c = shapeToBeDrawn.length;
CGFloat alpha = -asin(a/c);
CGRect r = CGRectMake(shapeToBeDrawn.startPoint.x, shapeToBeDrawn.startPoint.y - 30, shapeToBeDrawn.endPoint.x - shapeToBeDrawn.startPoint.x, 20);
[self drawText:lengthStr withFrame:r withFont:[UIFont fontWithName:#"Helvetica" size:18.0f] rotation:alpha alignment:NSTextAlignmentCenter context:context];
There im calculation the angle alpha and pass the string i want to display. And also create the frame for the text above the frame of the shape.
Here a small video how it looks currently:
Click
Hope someone can help me and my problem is clear. Thanks :)
To calculate angle properly in all quadrants, use atan2 function
alpha = atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x)
To define a rect - calculate starting coordinates for rotated rectangle:
x0 = startPoint.x + Sin(alpha) * 30
y0 = startPoint.y - Cos(alpha) * 30
rect.width = shapeToBeDrawn.length

Roof over square root symbol

I want to write a UILabel that can print square root expressions with a roof on it instead of just a simple √x. There should be a line over the x there as if it's written on paper.
Using Quartz 2D (the QuartzCore framework), you could just draw the line over it:
Thus, given
self.label.text = #"√23+45";
[self addSquareRootTopTo:self.label];
This would draw a line over the characters after the √ symbol:
- (void)addSquareRootTopTo:(UILabel *)label
{
NSRange range = [label.text rangeOfString:#"√"];
if (range.location == NSNotFound)
return;
NSString *stringThruSqrtSymbol = [label.text substringToIndex:range.location + 1];
NSString *stringAfterSqrtSymbol = [label.text substringFromIndex:range.location + 1];
CGSize sizeThruSqrtSymbol;
CGSize sizeAfterSqrtSymbol;
// get the size of the string given the label's font
if ([stringThruSqrtSymbol respondsToSelector:#selector(sizeWithAttributes:)])
{
// for iOS 7
NSDictionary *attributes = #{NSFontAttributeName : label.font};
sizeThruSqrtSymbol = [stringThruSqrtSymbol sizeWithAttributes:attributes];
sizeAfterSqrtSymbol = [stringAfterSqrtSymbol sizeWithAttributes:attributes];
}
else
{
// for earlier versions of iOS
sizeThruSqrtSymbol = [stringThruSqrtSymbol sizeWithFont:label.font];
sizeAfterSqrtSymbol = [stringAfterSqrtSymbol sizeWithFont:label.font];
}
// create path for line over the stuff after the square root sign
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(label.frame.origin.x + sizeThruSqrtSymbol.width, label.frame.origin.y)];
[path addLineToPoint:CGPointMake(label.frame.origin.x + sizeThruSqrtSymbol.width + sizeAfterSqrtSymbol.width, label.frame.origin.y)];
// now add that line to a CAShapeLayer
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.lineWidth = 1.0;
layer.strokeColor = [[UIColor blackColor] CGColor];
layer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:layer];
}
That yields a less than satisfactory gap:
You could play around with this to nudge the top of the square root symbol down, but the alternative approach would be to use Quartz 2D to draw the entire square root symbol. Thus, take the square root symbol out of the label's text value:
self.label.text = #"23+45";
[self addSquareRootTo:self.label];
And then draw the whole square root symbol in Quartz 2D:
static CGFloat const part1 = 0.12; // tiny diagonal will be 12% of the height of the text frame
static CGFloat const part2 = 0.35; // medium sized diagonal will be 35% of the height of the text frame
- (void)addSquareRootTo:(UILabel *)label
{
CGSize size;
if ([label.text respondsToSelector:#selector(sizeWithAttributes:)])
{
NSDictionary *attributes = #{NSFontAttributeName : label.font};
size = [label.text sizeWithAttributes:attributes];
}
else
{
size = [label.text sizeWithFont:label.font];
}
UIBezierPath *path = [UIBezierPath bezierPath];
// it's going to seem strange, but it's probably easier to draw the square root size
// right to left, so let's start at the top right of the text frame
[path moveToPoint:CGPointMake(label.frame.origin.x + size.width, label.frame.origin.y)];
// move to the top left
CGPoint point = CGPointMake(label.frame.origin.x, label.frame.origin.y);
[path addLineToPoint:point];
// now draw the big diagonal line down to the bottom of the text frame (at 15 degrees)
point.y += size.height;
point.x -= sinf(15 * M_PI / 180) * size.height;
[path addLineToPoint:point];
// now draw the medium sized diagonal back up (at 30 degrees)
point.y -= size.height * part2;
point.x -= sinf(30 * M_PI / 180) * size.height * part2;
[path addLineToPoint:point];
// now draw the tiny diagonal back down (again, at 30 degrees)
point.y += size.height * part1;
point.x -= sinf(30 * M_PI / 180) * size.height * part1;
[path addLineToPoint:point];
// now add the whole path to our view
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.lineWidth = 1.0;
layer.strokeColor = [[UIColor blackColor] CGColor];
layer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:layer];
}
That looks a little better:
Clearly, you can implement this any way you want (using either of the above, or probably better, subclassing a UIView to putting this, or its CoreGraphics equivalent, in drawRect), but it illustrates the idea of drawing the square root symbol yourself.
By the way, if using Xcode version prior 5, you'll have to manually add the QuartzCore.framework to your project and then include the appropriate header:
#import <QuartzCore/QuartzCore.h>

iOS drawRect with custom height

I have placed a view on a viewController and I want to draw a rectangle in this view, but with a custom height. I determine the height based on a parameter in my viewController.
So for example. If my parameter is 50, I want the rectangle to have the height of 50% of the UIView.
2 questions:
how can I pass the height to the custom drawRect?
how do I make the rectangle be placed on the bottom of the UIView?
I have placed the view using Interface Builder and I have implemented the drawRect in a subclass of UIView and used this as Custom Class for my UIView.
So in the custom class I have:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * lightGrayColor = [UIColor colorWithRed:230.0/255.0 green:230.0/255.0 blue:230.0/255.0 alpha:1.0];
CGRect paperRect = self.bounds;
drawLinearGradient(context, paperRect, lightGrayColor.CGColor, [UIColor clearColor].CGColor);
}
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = { 0.0, 1.0 };
NSArray *colors = #[(__bridge id) startColor, (__bridge id) endColor];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
This draws a nice gradient rectangle in my view but it fills the complete UIView.
This is because of the self.bounds.
I have added a property *height to my custom class, but I don't know how to fill this from my viewController. So I want it to start at the bottom off the UIView, and make it as high as I have determined (a % of the real height).
Anybody knows how I can achieve this?
have you set your custom view class in identity inspector in interface builder?
you can set the height property from your viewController:
((MyViewClass *) self.myView).height = myCalculatedValue;
then implement drawRect:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * lightGrayColor = [UIColor colorWithRed:230.0/255.0 green:230.0/255.0 blue:230.0/255.0 alpha:1.0];
CGRect paperRect = self.bounds;
paperRect.origin.y = paperRect.size.height - self.height;
paperRect.size.height = self.height;
//assuming your height property is of CGFloat type
drawLinearGradient(context, paperRect, lightGrayColor.CGColor, [UIColor clearColor].CGColor);
}
this will draw your gradient from (height) points above the bottom to the bottom
I think you can get calculate 50% of screen height and then substract new view height from the full screen Height
youParameter = 50; // Lets assume this is your parametere
int heightOfView = ([UIScreen mainScreen].bounds.size.height * yourParameter) / 100;
// For placing the view to the bottom;
CGRect newFrame;
frame.origin.y = [UIScreen mainScreen].bounds.size.height - heightOfView;
frame.origin.x = 0;
frame.size.width = [UIScreen mainScreen].bounds.size.width; // assuming it will take full width
frame.size.height = heightOfView;
youViewToChange.frame = newFrame; // normally do this or
To pass the value to drawRect you can do:
[self drawRect:newFrame];

Why isn't this random color method working?

I have a for loop inside the drawRect method that draws a number of circles to fill the screen. I'm trying to make it so each circle has a new random stroke. For some reason nothing is showing up. Here is my randomColor method:
-(UIColor *) randomColor
{
int red, green, blue, alpha;
red = arc4random_uniform(255);
green = arc4random_uniform(255);
blue = arc4random_uniform(255);
alpha = arc4random_uniform(255);
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red green:green blue:blue alpha:alpha];
return colorToReturn;
}
and I try implementing it here:
-(void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
// Firgure out the center of the bounds rectangle
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
// The radius of the circle should be nearly as big as the view
float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
// The thickness of the line should be 10 points wide
CGContextSetLineWidth(ctx, 10);
// The color of the line should be gray (red/green/blue = 0.6, alpha = 1.0)
// CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);
// The same as
// [[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] setStroke];
// The same as
// [[UIColor redColor] setStroke];
// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
// Add a path to the context
CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
[[self randomColor] setStroke];
// Perform drawing instructions; removes path
CGContextStrokePath(ctx);
}
UIColor takes a float between 0 and 1 as a value for its RGB components:
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:alpha];
I use the two macros below to get a random color. The first one is a straightforward macro that I often use while setting colors. The second one returns a random color using it:
#define _RGB(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
#define kCLR_RANDOM_COLOR _RGB(arc4random()%255, arc4random()%255, arc4random()%255, 1)

Calculating size of Text Rectangle area based on map zoomScale

I have custom mapOverlayView that display a text on a map using this code:
- (void)drawMapRect:(MKMapRect)mapRect
zoomScale:(MKZoomScale)zoomScale
inContext:(CGContextRef)ctx
{
[super drawMapRect:mapRect zoomScale:zoomScale inContext:ctx];
NSString *t=text2display;
CGPoint point = CGPointMake(0,30);
CGFloat fontSize = (3 * MKRoadWidthAtZoomScale(zoomScale));
UIFont *font = [UIFont fontWithName:#"Helvetica-Bold" size:fontSize];
// Draw outlined text.
CGContextSetTextDrawingMode(ctx, kCGTextStroke);
// Make the thickness of the outline a function of the font size in use.
CGContextSetLineWidth(ctx, fontSize/18);
CGContextSetStrokeColorWithColor(ctx, [[UIColor blackColor] CGColor]);
[t drawAtPoint:point withFont:font];
CGContextRestoreGState(ctx);
UIGraphicsPopContext();
I have also a corresponding mapOverlay that create the rectangle area of the text:
- (MKMapRect)boundingMapRect
{
MKMapRect bounds = MKMapRectMake(upperLeft.x, upperLeft.y-Z , 2000, 2000);
return bounds;
}
I need the bottom line of text to always stay at same level. Thus, I need to change the value of Z in the above code depending on the size of text to be drawn.
The size of text depends on zoomScale of the map. Is there away to know the zoom scale of the map? so that I could calculate the size of the text.

Resources