Draw a line between two points - How to pass UIView - uiview

I am trying to draw a simple line connecting two points. I think i got the right code for that in my drawLine method. No lines appear at all and I am pretty sure it has to do with the View I am calling with and the one I want to draw on. The following code is where I build my next View in code (data coming from a web service). The View gets created just fine and all buttons and objects appear.
I am trying to add lines to the View I'm creating (Next) dynamically and not sure how to get that done. From the Errors I get (invalid context 0x0) it seems I am doing something out of order. Trying to display on a view that is not there. how than can I get this done? Any advice would be appreciated.
I realize that passing on the View might not be the right answer. I am in the midst of trial and error here.
To clarify: I am calling drawLine here:
[nextView.view addSubview:next];
Thanks,
Shai
-(void) drawView
{
CGRect rec;
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
UIView *next = [[UIView alloc]initWithFrame:CGRectMake(0, 0, height, width)];
next.backgroundColor = [UIColor whiteColor];
next.userInteractionEnabled = YES;
next.multipleTouchEnabled = YES;
nextView = [UIViewController alloc];
[nextView setTitle: as_objectDesc];
for (object in viewObjects)
{ // ratio based on Ipad 2 screen size conversion from the Datawindow size - alter to support other device
CGFloat objWidth = object.Width/3.83;
CGFloat objHeight = object.Height/2.78;
CGFloat objXPoint = object.positionX/3.83;
CGFloat objYPoint = object.positionY/2.78;
if ([object.Shape isEqualToString:#"text"])
{
rec = CGRectMake(objXPoint, objYPoint, objWidth, objHeight);
UILabel *myLabel = [[UILabel alloc] initWithFrame:rec];
myLabel.backgroundColor = [UIColor clearColor];
myLabel.text = object.objectTag;
myLabel.lineBreakMode = NSLineBreakByWordWrapping;
if ([object.description isEqualToString:#"Header"])
{
myLabel.font = [UIFont systemFontOfSize:20];
}
else
{
myLabel.font = [UIFont systemFontOfSize:10];
}
[next addSubview:myLabel];
}
else if ([object.Shape isEqualToString:#"line"])
{
**[self drawLine:nextView.view];**
}
else
{
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
if ([object.Shape isEqualToString:#"ellipse"])
{
UIImage * buttonImage;
if ([object.Color isEqualToString:#"255"])
{
buttonImage = [UIImage imageNamed:#"redBackground.png"];
}
else if ([object.Color isEqualToString:#"65535"])
{
buttonImage = [UIImage imageNamed:#"yellowBackground.png"];
}
else if ([object.Color isEqualToString:#"GRAY"])
{
buttonImage = [UIImage imageNamed:#"graybground.PNG"];
}
else if ([object.Color isEqualToString:#"BLACK"])
{
buttonImage = [UIImage imageNamed:#"BlackBackground.png"];
}
[myButton setBackgroundImage:buttonImage forState: UIControlStateNormal];
objWidth = objHeight;
rec = CGRectMake(objXPoint, objYPoint, objWidth, objHeight);
myButton.frame = rec;
myButton.clipsToBounds = YES;
myButton.layer.cornerRadius = objWidth/2;
}
else
{
rec = CGRectMake(objXPoint, objYPoint, objWidth, objHeight);
if ([object.Color isEqualToString:#"255"])
myButton.backgroundColor = [UIColor redColor];
else if ([object.Color isEqualToString:#"65535"])
myButton.backgroundColor = [UIColor yellowColor];
else if ([object.Color isEqualToString:#"GRAY"])
myButton.backgroundColor = [UIColor grayColor];
else if ([object.Color isEqualToString:#"BLACK"])
myButton.backgroundColor = [UIColor blackColor];
}
[[myButton layer] setBorderWidth:1.0f];
[[myButton layer] setBorderColor:[UIColor blackColor].CGColor];
myButton.enabled = YES;
myButton.accessibilityHint = object.objectTag;
myButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
myButton.titleLabel.textAlignment = NSTextAlignmentCenter;
myButton.titleLabel.font = [UIFont systemFontOfSize:13];
[myButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
myButton.frame = rec;
[myButton setTitle:object.description forState:UIControlStateNormal];
// Check if an Empty Rectangle
NSRange test =[myButton.accessibilityHint rangeOfString:#"r_"];
if (test.location == 0)
{
[next sendSubviewToBack:myButton];
[myButton setEnabled:NO];
}
[next addSubview:myButton];
}
UIPinchGestureRecognizer *twoFingerPinch = [[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(twoFingerPinch:)]
;
[[nextView view] addGestureRecognizer:twoFingerPinch];
[next addSubview:activityIndicator];
[next bringSubviewToFront:activityIndicator];
}
[nextView.view addSubview:next];
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController pushViewController:nextView animated:NO];
}
- (void)drawLine:(UIView *) view
{
CGFloat x1 = object.positionX;
CGFloat y1 = object.positionY;
CGFloat x2 = object.positionX2;
CGFloat y2 = object.positionY2;
CGContextRef context = UIGraphicsGetCurrentContext();
if ([object.Color isEqualToString:#"255"])
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
else if ([object.Color isEqualToString:#"65535"])
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
else if ([object.Color isEqualToString:#"GRAY"])
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
else if ([object.Color isEqualToString:#"BLACK"])
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 3.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, x1, y1);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
}

I end up figuring this up days a go and thought I would share here. I might have added to much code in my question which did not help to simplify it to others (no comments).
What this came down to is when trying to Draw a line you need to override the DrawRect Method of the UIView subclass and not the UIViewController as I did. There is no Error thrown if you call DrawRect from your UIViewController but it doesn't do anything. I missed that small detail.
What added to the complexity of finding this out ans solving this was that I was creating all of it Programmatically and initially didn't subclass UIView at all. I ended up adding all the Points in an NSMutablearray and redrawing the lines in the following class after the newly View got created:
#import "draw.h"
#implementation draw
#synthesize lines;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
}
return self;
}
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
for (line *myLine in lines)
{
if ([myLine.color isEqualToString:#"255"])
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
else if ([myLine.color isEqualToString:#"65535"])
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
else if ([myLine.color isEqualToString:#"GRAY"])
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
else if ([myLine.color isEqualToString:#"BLACK"])
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
int setNew = myLine.Width/4;
CGContextSetLineWidth(context, (CGFloat)setNew);
CGContextBeginPath(context);
CGContextMoveToPoint(context, myLine.x1, myLine.y1);
CGContextAddLineToPoint(context, myLine.x2, myLine.y2);
CGContextStrokePath(context);
}
}
#end

Related

Scale image based off UIPinch

I am so confused with how to do what I need! Any help is very appreciated! I have an transparent image overlay that has another image behind it that has a UIPanGestureRecognizer and a UIPinchGestureRecognizer attached to it. The top image has a completely transparent middle that serves as the "glass" view. I am trying to crop the bottom image to the "glass" part based off pan and pinch. (see the image below to see what i'm talking about) I have successfully taken care of the pan crop but am having issues cropping it correctly when pinch is also applied.
I am not using snapshotViewAfterScreenUpdates.
Here is the code I have so far:
UIImage *snapshotImage;
/* draw the image of all the views below our view */
UIGraphicsBeginImageContextWithOptions(self.pendantImageView.bounds.size, NO, 0);
BOOL successfulDrawHierarchy = [self.pendantImageView drawViewHierarchyInRect:self.pendantImageView.bounds afterScreenUpdates:YES];
if ( successfulDrawHierarchy ) {
snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
} else {
NSLog(#"drawViewHierarchyInRect:afterScreenUpdates: failed - there's nothing to draw...");
}
UIGraphicsEndImageContext();
UIImage *croppedImage;
if ( successfulDrawHierarchy ) {
/* calculate the coordinates of the rectangle we're interested in within the returned image */
CGRect cropRect = CGRectOffset(pendantFrame, - self.pendantImageView.frame.origin.x, - self.pendantImageView.frame.origin.y);
/* draw the cropped section with a clipping region */
UIGraphicsBeginImageContextWithOptions(cropRect.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, cropRect.size.width, cropRect.size.height));
CGRect targetRectangeForCrop = CGRectMake(-cropRect.origin.x, -cropRect.origin.y, snapshotImage.size.width, snapshotImage.size.height);
[snapshotImage drawInRect:targetRectangeForCrop];
croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
pendantImageView is the bottom imageView and pendantFrame is the middle coords of the area i'm trying to crop to.
Thanks in advance!
I am not sure whether I understood you correctly, but here is my result:
(click on the video to watch full version)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIImageView *theImageView = [UIImageView new];
[self.view addSubview:theImageView];
theImageView.image = [UIImage imageNamed:#"image1.jpg"];
theImageView.frame = self.view.frame;
theImageView.userInteractionEnabled = YES;
theImageView.alpha = 0.6;
UIImageView *thePanImageView = [UIImageView new];
[self.view addSubview:thePanImageView];
thePanImageView.frame = CGRectMake(0, 0, 100, 100);
thePanImageView.center = CGPointMake(theImageView.frame.size.width/2, theImageView.frame.size.height/2);
thePanImageView.image = [self screenshotFromRect:thePanImageView.frame fromView:theImageView];
thePanImageView.userInteractionEnabled = YES;
thePanImageView.layer.cornerRadius = thePanImageView.frame.size.width/2;
thePanImageView.clipsToBounds = YES;
thePanImageView.theWeakObject = theImageView;
{
UIPanGestureRecognizer *thePanGesture = [UIPanGestureRecognizer new];
[thePanGesture addTarget:self action:#selector(handlePanGesture:)];
[thePanImageView addGestureRecognizer:thePanGesture];
UIPinchGestureRecognizer *thePinchGesture = [UIPinchGestureRecognizer new];
[thePinchGesture addTarget:self action:#selector(handlePinchGesture:)];
[thePanImageView addGestureRecognizer:thePinchGesture];
}
}
- (void)handlePanGesture:(UIPanGestureRecognizer *)thePanGesture
{
UIImageView *thePanImageView = (id)thePanGesture.view;
UIImageView *theImageView = thePanImageView.theWeakObject;
thePanImageView.center = [thePanGesture locationInView:theImageView];
thePanImageView.image = [self screenshotFromRect:thePanImageView.frame fromView:theImageView];
}
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)thePinchGesture
{
UIImageView *thePanImageView = (id)thePinchGesture.view;
static CGRect theInitialFrame;
if (thePinchGesture.state == UIGestureRecognizerStateBegan)
{
theInitialFrame = thePanImageView.frame;
}
else
{
CGRect theFrame = theInitialFrame;
theFrame.size.width *= thePinchGesture.scale;
theFrame.size.height *= thePinchGesture.scale;
thePanImageView.frame = theFrame;
}
thePanImageView.layer.cornerRadius = thePanImageView.frame.size.width/2;
UIImageView *theImageView = thePanImageView.theWeakObject;
thePanImageView.center = [thePinchGesture locationInView:theImageView];
thePanImageView.image = [self screenshotFromRect:thePanImageView.frame fromView:theImageView];
}
- (UIImage * __nonnull)screenshotFromRect:(CGRect)theRect fromView:(UIView * __nonnull)theView;
{
if (!theView)
{
abort();
}
if (theRect.size.height < 1 || theRect.size.width < 1)
{
abort();
}
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
{
UIGraphicsBeginImageContextWithOptions(theRect.size, YES, [UIScreen mainScreen].scale);
}
else
{
UIGraphicsBeginImageContext(theRect.size);
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, -theRect.origin.x, -theRect.origin.y);
[theView.layer renderInContext:ctx];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
EDIT:
The above solution is inefficient in terms of CPU, because it takes screenshots every time you move the view.
A much more efficient way would be to create an extra UIImageView, and simply move it inside of your thePanImageView
The code is the following:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIImageView *theImageView = [UIImageView new];
[self.view addSubview:theImageView];
theImageView.image = [UIImage imageNamed:#"image1.jpg"];
theImageView.frame = self.view.frame;
theImageView.userInteractionEnabled = YES;
theImageView.alpha = 0.6;
UIImageView *thePanImageView = [UIImageView new];
[self.view addSubview:thePanImageView];
thePanImageView.frame = CGRectMake(0, 0, 100, 100);
thePanImageView.center = CGPointMake(theImageView.frame.size.width/2, theImageView.frame.size.height/2);
thePanImageView.userInteractionEnabled = YES;
thePanImageView.layer.cornerRadius = thePanImageView.frame.size.width/2;
thePanImageView.clipsToBounds = YES;
thePanImageView.layer.borderColor = [UIColor redColor].CGColor;
thePanImageView.layer.borderWidth = 1;
thePanImageView.theWeakObject = theImageView;
{
UIPanGestureRecognizer *thePanGesture = [UIPanGestureRecognizer new];
[thePanGesture addTarget:self action:#selector(handlePanGesture:)];
[thePanImageView addGestureRecognizer:thePanGesture];
UIPinchGestureRecognizer *thePinchGesture = [UIPinchGestureRecognizer new];
[thePinchGesture addTarget:self action:#selector(handlePinchGesture:)];
[thePanImageView addGestureRecognizer:thePinchGesture];
UIImageView *theExtraImageView = [UIImageView new];
[thePanImageView addSubview:theExtraImageView];
theExtraImageView.frame = CGRectMake(-thePanImageView.frame.origin.x, -thePanImageView.frame.origin.y, theImageView.frame.size.width, theImageView.frame.size.height);
theExtraImageView.image = theImageView.image;
}
}
- (void)handlePanGesture:(UIPanGestureRecognizer *)thePanGesture
{
UIImageView *thePanImageView = (id)thePanGesture.view;
UIImageView *theImageView = thePanImageView.theWeakObject;
thePanImageView.center = [thePanGesture locationInView:theImageView];
UIImageView *theExtraImageView = thePanImageView.subviews.firstObject;
theExtraImageView.frame = CGRectMake(-thePanImageView.frame.origin.x, -thePanImageView.frame.origin.y, theExtraImageView.frame.size.width, theExtraImageView.frame.size.height);
}
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)thePinchGesture
{
UIImageView *thePanImageView = (id)thePinchGesture.view;
static CGRect theInitialFrame;
if (thePinchGesture.state == UIGestureRecognizerStateBegan)
{
theInitialFrame = thePanImageView.frame;
}
else
{
CGRect theFrame = theInitialFrame;
theFrame.size.width *= thePinchGesture.scale;
theFrame.size.height *= thePinchGesture.scale;
thePanImageView.frame = theFrame;
}
thePanImageView.layer.cornerRadius = thePanImageView.frame.size.width/2;
UIImageView *theImageView = thePanImageView.theWeakObject;
thePanImageView.center = [thePinchGesture locationInView:theImageView];
UIImageView *theExtraImageView = thePanImageView.subviews.firstObject;
theExtraImageView.frame = CGRectMake(-thePanImageView.frame.origin.x, -thePanImageView.frame.origin.y, theExtraImageView.frame.size.width, theExtraImageView.frame.size.height);
}
FYI:
theWeakObject is just my custom property to NSObject. I used it because I was lazy and didn't want to create globally-visible #property
you should ask for how to output a image use mask! here is the link for the solution:
CGContextClipToMask returning blank image
you need to change:
CGContextClipToRect(context, CGRectMake(0, 0, cropRect.size.width, cropRect.size.height));
to something like:
CGContextClipToMask(context, CGRectMake(0, 0, cropRect.size.width, cropRect.size.height), maskImage);

How to disable Customized UIButton

I subclassed UIButton and did some customized drawing in drawRect method such as drawing NSAttributedString and UIImage.
However, after I did this, the customized UIButton doesn't gray out when enabled is set to NO. I think my customized drawing happens on top of its state. How do I deal with this?
Sharing my drawing code here:
- (void)drawRect:(CGRect)rect
{
// Drawing code
if (self.faceUp) {
[self drawCardText:self.card.contents inRect:self.bounds];
} else {
[self drawCardImage:[UIImage imageNamed:CardBackImageName] inRect:self.bounds];
}
}
- (void)drawCardText:(NSString *)text inRect:(CGRect)rect
{
// set background color to white so text can be shown
[[UIColor whiteColor] setFill];
[[UIBezierPath bezierPathWithRect:rect] fill];
UIFont *preferedFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
UIFont *actualFont = [UIFont fontWithName:preferedFont.fontName
size:hypotf(rect.size.width, rect.size.height) / 6.0];
NSDictionary *attributes = #{NSFontAttributeName: actualFont};
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];
[self setAttributedTitle:attributedText forState:UIControlStateNormal];
}
- (void)drawCardImage:(UIImage *)image inRect:(CGRect)rect
{
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.0f);
[image drawInRect:rect];
UIImage *actualImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[UIColor colorWithPatternImage:actualImage] setFill];
[[UIBezierPath bezierPathWithRect:rect] fill];
}
You might have to add an overlay view with grey color and some alpha yourself. Remove the overlay when button is enabled again.
You can add this method to CustomButton class.
-(void)setEnabled:(BOOL)enabled{
//disableLayer.hidden = !enabled;
if (enabled) {
//self.enabled = YES;
self.alpha = 1.0;
}else{
//self.enabled = NO;
self.alpha = 0.7;
}
[super setEnabled:enabled];
}
For enable or disable call-
[customButtob setEnabled:buttonStatus];
If you want to change color, add a background layer, and toggle its hidden property in setEnabled method.
disableLayer = [CALayer layer];
disableLayer.backgroundColor = [UIColor colorWithRed:20/255.0f green:20/255.0f blue:20/255.0f alpha:1.0f].CGColor;
disableLayer.frame = self.layer.bounds;
disableLayer.hidden = YES;
[self.layer insertSublayer:disableLayer below:otherLayer];
I think you share some more details of your implementation. Moreover I am sure you have called
Super methods in the customized methods at first call.
You have to override the setEnabled: method of your CustomButton
-(void)setEnabled:(BOOL)enabled
{
if (!enabled) {
[self setAlpha:0.2f];
}
}
OR
If you have to change the color of UIButton in its disabled state. Yo can change drawRect: method as
Make a assign property of BOOL type variable (say isEnabled)
-(void)drawRect:(CGRect)rect
{
[[UIColor redColor] setFill];
UIRectFill(rect);
if (!self.isEnabled) {
[[UIColor blackColor] setFill];
UIRectFill(rect);
}
}
-(void)setEnabled:(BOOL)enabled
{
self.isEnabled = enabled;
[self setNeedsDisplay];
}
You can use
btn.userInteractionEnabled = NO;
Or you can use
btn.enabled = NO;
Hope this helps... :)
Edit:
I think you can use this
[btn setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
Add this:
-(void)setEnabled:(BOOL)enabled{
if (!enabled) {
self.alpha = 0.3;
}else{
self.alpha = 1.0;
}
[super setEnabled:enabled];
}
add a method which can help u for enable and disable of your button just add this method in custom button class
//in customButton.h file
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton
#property (nonatomic,assign) BOOL faceUp;//your property
- (void)makeButtonDisable:(BOOL)disable;//method to handle disable and enable
#end
//in customButton.m file
#import "CustomButton.h"
#implementation CustomButton
{
CALayer *grayLayer;//layer to handle disable and enable
}
#synthesize faceUp;
// in initilization method
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
grayLayer = [CALayer layer];
grayLayer.frame = frame;
[self.layer addSublayer:grayLayer]; //add the grayLayer during initialisation
}
return self;
}
//your code that put above
- (void)drawRect:(CGRect)rect
{
// Drawing code
if (self.faceUp) {
[self drawCardText:self.card.contents inRect:self.bounds];
} else {
[self drawCardImage:[UIImage imageNamed:CardBackImageName] inRect:self.bounds];
}
}
- (void)drawCardText:(NSString *)text inRect:(CGRect)rect
{
// set background color to white so text can be shown
[[UIColor whiteColor] setFill];
[[UIBezierPath bezierPathWithRect:rect] fill];
UIFont *preferedFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
UIFont *actualFont = [UIFont fontWithName:preferedFont.fontName
size:hypotf(rect.size.width, rect.size.height) / 6.0];
NSDictionary *attributes = #{NSFontAttributeName: actualFont};
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];
[self setAttributedTitle:attributedText forState:UIControlStateNormal];
}
- (void)drawCardImage:(UIImage *)image inRect:(CGRect)rect
{
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.0f);
[image drawInRect:rect];
UIImage *actualImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[UIColor colorWithPatternImage:actualImage] setFill];
[[UIBezierPath bezierPathWithRect:rect] fill];
}
//add this method
- (void)makeButtonDisable:(BOOL)disable
{
if(disable)
{
grayLayer.backgroundColor = [UIColor colorWithRed:201.0f/255.0f green:201.0f/255.0f blue:201.0f/255.0f alpha:5.0f].CGColor;
self.userInteractionEnabled = NO;
grayLayer.opacity = 0.5f;
self.alpha = 0.5f;
}
else
{
grayLayer.backgroundColor = [UIColor clearColor].CGColor;
self.userInteractionEnabled = YES;
grayLayer.opacity = 0.0f;
self.alpha = 1.0f;
}
}
in the controller where u are using this button
//some where in the controller u want to disable the button just do like this
//to disable
[button makeButtonDisable:YES]; //button is an instance of customCell
//to enable
[button makeButtonDisable:NO]; //button is an instance of customCell

iOS 7 UIButton alignment

I'm trying to make custom badge. For that I make subclass of UIButton and remake - (void)drawRect:(CGRect)rect like this:
- (void)drawRect:(CGRect)rect
{
self.titleLabel.font = [UIFont systemFontOfSize:12];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.userInteractionEnabled = NO;
self.layer.borderWidth = 1.5f;
self.layer.cornerRadius = rect.size.width / 2;
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
self.layer.backgroundColor = [UIColor grayColor].CGColor;
self.layer.borderColor = [UIColor grayColor].CGColor;
}
And everything is good except alignment. It is a little upper than it should be. Looks like this:
What to do?
#property(nonatomic) NSTextAlignment textAlignment;
// default is NSTextAlignmentLeft
It's an attribute of UILabel.
Here is badge I need: https://github.com/jessesquires/JSCustomBadge . Works perfect!

Draw text outside of CGRect.

I am using Apple's Sample Code TheElements for this question. How would I go about drawing text outside of the elementSymbolRectangle. For example I would like to display the Elements Name, but I need it to be outside of the elementSymbolRectangle. I am new to programming and would appreciate any help.
Thanks
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setAutoresizesSubviews:YES];
[self setupUserInterface];
// set the background color of the view to clearn
self.backgroundColor=[UIColor clearColor];
}
return self;
}
- (void)jumpToWikipedia:(id)sender {
// create the string that points to the correct Wikipedia page for the element name
NSString *wikiPageString = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/%#", self.element.name];
if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:wikiPageString]])
{
// there was an error trying to open the URL. for the moment we'll simply ignore it.
}
}
- (void)drawRect:(CGRect)rect {
// get the background image for the state of the element
// position it appropriately and draw the image
//
UIImage *backgroundImage = [self.element stateImageForAtomicElementView];
CGRect elementSymbolRectangle = CGRectMake(0, 0, [backgroundImage size].width, [backgroundImage size].height);
[backgroundImage drawInRect:elementSymbolRectangle];
// all the text is drawn in white
[[UIColor whiteColor] set];
// draw the element number
UIFont *font = [UIFont boldSystemFontOfSize:32];
CGPoint point = CGPointMake(10,5);
[[NSString stringWithFormat:#"%#", self.element.atomicNumber] drawAtPoint:point withFont:font];
// draw the element symbol
CGSize stringSize = [self.element.symbol sizeWithFont:font];
point = CGPointMake((self.bounds.size.width-stringSize.width-10),5);
[self.element.symbol drawAtPoint:point withFont:font];
This solved my problem.
UILabel *scoreLabel = [ [UILabel alloc ] initWithFrame:CGRectMake((self.bounds.size.width / 2), -50.0, 100.0, 100.0) ];
scoreLabel.textAlignment = UITextAlignmentCenter;
scoreLabel.textColor = [UIColor whiteColor];
scoreLabel.backgroundColor = [UIColor blackColor];
scoreLabel.font = [UIFont fontWithName:#"Arial Rounded MT Bold" size:(36.0)];
[self addSubview:scoreLabel];
scoreLabel.text = [NSString stringWithFormat: #"Test"];

CATiledLayer subview causing memory warning and crash [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Alright, here's what's happening... I have a UIView subclass, which includes two points (start and end), a CGPath between those two points and lot of UILabels. If I add that UIView subclass as a subview to my scrollview (over top of my CATiledLayer based UIView) then my app starts getting memory warnings and eventually crashes. However, if I remove the UIView subclass that contains the points and path and leave the CATiledLayer view as it is, everything functions perfectly and no crashing or memory warnings occur.
Does anyone have any ideas on why this is occurring? The content view shouldn't have any problems being so big should it since I'm only draw labels that are at max 40px wide and a CGPath, which is also pretty small?
This is a mapping application
Here's some code:
//Display the map image
- (void)displayTiledImageNamed:(NSString *)imageName size:(CGSize)imageSize {
self.zoomScale = 1.0;
container = [[UIView alloc] initWithFrame:(CGRect){ CGPointZero, imageSize }];
_zoomView = [[UIImageView alloc] initWithFrame:(CGRect){ CGPointZero, imageSize }];
NSString *path = [NSString stringWithFormat:#"%#/%#-Small.png",[[NSBundle mainBundle] bundlePath], [imageName stringByDeletingPathExtension]];
UIImage *zoomImage = [UIImage imageWithContentsOfFile:path];
[_zoomView setImage:zoomImage];
[container addSubview:_zoomView];
[_zoomView release];
_tilingView = [[UMTileView alloc] initWithImageName:imageName size:imageSize];
_tilingView.frame = _zoomView.bounds;
[_zoomView addSubview:_tilingView];
[_tilingView release];
[self configureForImageSize:imageSize];
//This is the view that's causing the crash and memory warnings
//If this view is commented out the app functions just fine
UMMapContentView *m = [[UMMapContentView alloc] initWithFrame:CGRectMake(0,0,imageSize.width,imageSize.height) andColors:self.colors mapView:self.mapView];
self.contentView = m;
[container addSubview:self.contentView];
[m release];
[self addSubview:container];
[container release];
}
This my path view class which is another subview inside the UMMapContentView view above:
+ (Class)layerClass {
return [CATiledLayer class];
}
+ (CFTimeInterval)fadeDuration {
return 0.0;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.userInteractionEnabled = NO;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)dealloc {
self.path = nil;
self.pathColor = nil;
[super dealloc];
}
- (void)resetPathView {
CATiledLayer *tiledLayer = (CATiledLayer*)self.layer;
tiledLayer.contents = nil;
[tiledLayer setNeedsDisplay];
}
- (void)drawPath:(UMPath*)p {
self.path = p;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
if (self.path) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, self.pathColor.CGColor);
CGContextSetShadowWithColor(context, CGSizeMake(2.0, 1.0), 1.0, [[UIColor colorWithWhite:0.2 alpha:0.8] CGColor]);
CGContextSetLineWidth(context, 8.0);
CGContextBeginPath (context);
CGContextMoveToPoint (context, ((UMMapPoint*)[self.path.points objectAtIndex: 0]).x, ((UMMapPoint*)[self.path.points objectAtIndex: 0]).y);
for (int i = 1; i < self.path.points.count; i++) {
CGContextAddQuadCurveToPoint (context, ((UMMapPoint*)[self.path.points objectAtIndex:i-1]).x, ((UMMapPoint*)[self.path.points objectAtIndex: i-1]).y, ((UMMapPoint*)[self.path.points objectAtIndex:i]).x, ((UMMapPoint*)[self.path.points objectAtIndex:i]).y);
}
CGContextStrokePath (context);
}
}
And this is my method that places all the UILabels in the UMMapContentView view:
- (void)mapAllLabelsInNavigationMap:(int)navigationMap {
//There are 1109 label dictionaries in the labels array
for (NSDictionary *dict in labels) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake([[dict objectForKey:#"X"] floatValue],[[dict objectForKey:#"Y"] floatValue],[[dict objectForKey:#"Width"] floatValue],[[dict objectForKey:#"Height"] floatValue])];
[label setLineBreakMode:NSLineBreakByWordWrapping];
[label setNumberOfLines:0];
[label setBackgroundColor:[UIColor clearColor]];
[label setTextColor:[self colorFromHexString:[dict objectForKey:#"Foreground"]]];
[label setFont:[UIFont systemFontOfSize:[[dict objectForKey:#"FontSize"] floatValue]]];
[label setTextAlignment:NSTextAlignmentCenter];
[label setText:[[UMDataBase shared] stringForID:[[dict objectForKey:#"Texts_ID"] intValue] withLanguage:languageID]];
[self addSubview:label];
[localMapLabels addObject:label];
[label release];
}
}
I'm not really sure what direction I need to head... Any help would be much appreciated! :)
You did not give the source code of UMMapContentView, but if it uses CATiledLayer, then that may be the problem. It seems that you cannot subview a CATiledLayer-backed view.
Scroll to the bottom (in the comments section): http://red-glasses.com/index.php/tutorials/catiledlayer-how-to-use-it-how-it-works-what-it-does/
It may be easier if you write your own tiled layer anyhow. Documentation on CATiledLayer is sparse while the bugs are aplenty.

Resources