This seems like a dumb question or maybe I'm just tired but I'm not getting the results I want. I'm not sure I'm getting any results since I can't see my lines. Can someone please tell me what I am doing wrong?
- (void)drawCenterPlus
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 20);
[[UIColor redColor] setStroke];
CGPoint hStart;
CGPoint hEnd;
CGPoint vStart;
CGPoint vEnd;
hStart.x = self.center.x - 20.0;
hStart.y = self.center.y;
hEnd.x = self.center.x + 20.0;
hEnd.y = self.center.y;
vStart.x = self.center.x;
vStart.y = self.center.y - 20.0;
vEnd.x = self.center.x;
vEnd.y = self.center.y + 20.0;
//line 1
CGContextBeginPath(context);
CGContextMoveToPoint(context, hStart.x, hStart.y);
CGContextAddLineToPoint(context, hEnd.x, hEnd.y);
CGContextStrokePath(context);
//line 2
CGContextBeginPath(context);
CGContextMoveToPoint(context, vStart.x, vStart.y);
CGContextAddLineToPoint(context, vEnd.x, vEnd.y);
CGContextStrokePath(context);
}
Thank you in advance.
------------------------------------------------------- Additional Info ------------------------------------------
Actually this is called from viewDidLoad. I am just trying to draw a "+" in the center of the view. I've made the view a different color, so that the "+" can be seen. The "+" can be drawn in black, I just want to be able to see it. Yes, I could put a text "+" on the screen but ultimately I need to draw it inside of a rectangle.
I'm going to try again with a blank view to see if the drawing is hiding behind a subview. We'll see. Thank you again for your help.
------------------------------------------------------- Latest Method -----------------------------------------------
OK. Just a new project with one view that only has (hopefully) the red "+" in the middle of the screen. But nothing displays. What am I doing wrong?
#implementation TESTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 20);
[[UIColor redColor] setStroke];
CGPoint hStart;
CGPoint hEnd;
CGPoint vStart;
CGPoint vEnd;
hStart.x = self.view.center.x - 20.0;
hStart.y = self.view.center.y;
hEnd.x = self.view.center.x + 20.0;
hEnd.y = self.view.center.y;
vStart.x = self.view.center.x;
vStart.y = self.view.center.y - 20.0;
vEnd.x = self.view.center.x;
vEnd.y = self.view.center.y + 20.0;
//line 1
CGContextBeginPath(context);
CGContextMoveToPoint(context, hStart.x, hStart.y);
CGContextAddLineToPoint(context, hEnd.x, hEnd.y);
CGContextStrokePath(context);
//line 2
CGContextBeginPath(context);
CGContextMoveToPoint(context, vStart.x, vStart.y);
CGContextAddLineToPoint(context, vEnd.x, vEnd.y);
CGContextStrokePath(context);
}
Check the value of context - I'm guessing it may be nil.
If you put this code inside a UIView subclass's drawRect method it should work as you will have a valid context.
Alternatively, you could create your own UIImage context, draw the shape in that and add the image as a subview. E.g.
- (void)drawCenterPlus {
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 20);
[[UIColor redColor] setStroke];
CGPoint hStart;
CGPoint hEnd;
CGPoint vStart;
CGPoint vEnd;
hStart.x = self.view.center.x - 20.0;
hStart.y = self.view.center.y;
hEnd.x = self.view.center.x + 20.0;
hEnd.y = self.view.center.y;
vStart.x = self.view.center.x;
vStart.y = self.view.center.y - 20.0;
vEnd.x = self.view.center.x;
vEnd.y = self.view.center.y + 20.0;
//line 1
CGContextBeginPath(context);
CGContextMoveToPoint(context, hStart.x, hStart.y);
CGContextAddLineToPoint(context, hEnd.x, hEnd.y);
CGContextStrokePath(context);
//line 2
CGContextBeginPath(context);
CGContextMoveToPoint(context, vStart.x, vStart.y);
CGContextAddLineToPoint(context, vEnd.x, vEnd.y);
CGContextStrokePath(context);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:imageView];
}
CGContextRef context = UIGraphicsGetCurrentContext(); will be nil at this point... you basically want to add this code to your drawing code, unless you want to add static views or images to represent the cross.
The current Context wont be your view object unless it is has focus, which happens automatically by the time the drawRect: method is called.
you can alternately draw to an image and add it to an image view, you can do that in did load, and the drawing will happen automatically from that point on.
Related
I want to draw lines in a UIView with based the UIView's height. (i.e) line height should be equal to the UIView's height. For that i'm using the following code.
- (void)testDraw :(void(^)(UIImage *image, UIImage *selectedImage))done
{
CGSize imageSize = CGSizeMake(1000, self.bounds.size.height);
//Begin the animation by checking the screen is retina / ordinary
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0f);
else
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
for (NSInteger intSample=0; intSample < 1000; intSample++) {
if(intSample % self.samplesPerSecond == 0){
//draw separator line
[self drawLine:context fromPoint:CGPointMake(intSample, 0) toPoint:CGPointMake(intSample, self.frame.size.height) color:self.lineColor lineWidth:2.0];
}
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGRect drawRect = CGRectMake(0, 0, image.size.width, self.frame.size.height);
[self.progressColor set];
UIRectFillUsingBlendMode(drawRect, kCGBlendModeSourceAtop);
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
done(image, tintedImage);
}
//Draw the line based on the value received
- (void) drawLine:(CGContextRef) context fromPoint:(CGPoint) fromPoint toPoint:(CGPoint) toPoint color:(UIColor*) color lineWidth:(float) lineWidth{
CGContextBeginPath(context);
//add the lines with sizes that u want
CGContextSetAlpha(context,1.0);
CGContextSetLineWidth(context, lineWidth);
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
}
When i execute the above code with it working fine in 3.5 inch display, It's working fine. But when i run the same code in 4-inch the line height is not increasing based on the UIView. The lines are not working as like auto layouts.
Thanks in advance, Can anyone give your suggestion to fix this issue.
I'm trying to draw a circle for my Mac Application. The Code is:
- (void)mouseMoved:(NSEvent*)theEvent {
NSPoint thePoint = [[self.window contentView] convertPoint:[theEvent locationInWindow] fromView:nil];
NSLog(#"mouse moved: %f % %f",thePoint.x, thePoint.y);
CGRect circleRect = CGRectMake(thePoint.x, thePoint.y, 20, 20);
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSetRGBFillColor(context, 0, 0, 255, 1.0);
CGContextSetRGBStrokeColor(context, 0, 0, 255, 0.5);
CGContextFillEllipseInRect(context, CGRectMake(circleRect.origin.x, circleRect.origin.y, 25, 25));
CGContextStrokeEllipseInRect(context, circleRect);
[self needsDisplay];
}
- (void)mouseMoved: is called perfectly and I can see the correct x and y coordinates in NSLog. But I do not get any circles... surprisingly: If I'm minimizing my application and reopening it (so it "updates" NSView) the circles are perfectly drawn!
mouseMoved is NOT right place to draw anything, unless you're drawing onto the offscreen buffer. If you are going to draw on screen, save thePoint and any other necessary data, call [self setNeedsDisplay:YES] and draw in the drawRect:(NSRect)rect method.
Also, I can't see a reason to use CGContextRef while there is much more "friendly" NSGraphicsContext. Although, it's matter of taste.
An example of the drawing code:
- (void)mouseMoved:(NSEvent*)theEvent {
// thePoint must be declared as the class member
thePoint = [[self.window contentView] convertPoint:[theEvent locationInWindow] fromView:nil];
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)rect
{
NSRect ovalRect = NSMakeRect(thePoint.x - 100, thePoint.y - 100, 200, 200);
NSBezierPath* oval = [NSBezierPath bezierPathWithOvalInRect:ovalRect];
[[NSColor blueColor] set];
[oval fill];
[[NSColor redColor] set];
[oval stroke];
}
I am creating a drawing application like this, but I have one issue. The problem is that when I draw a line with one color and then draw a line with another color, it gives me combination of both colors where the lines intersect.
- (void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextStrokePath(context);
[super drawRect:rect];
[curImage release];
}
The rest of the project is available on GitHub.
Maybe have a look at blend modes.
https://developer.apple.com/library/mac/#documentation/graphicsimaging/Reference/CGContext/Reference/reference.html#//apple_ref/c/tdef/CGBlendMode
I can draw a line by placing the following into a UIView and connecting it to a storyboard View.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 10, 50);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
However, what I want to do is to draw a line whenever a button is pressed. To do this I assume I need to write some code into an IBAction. My problem is that I cannot simply place the above code into the IBAction as it gives me an error.
- (IBAction)draw:(id)sender{
//Place code here
}
My question is, how can I draw a line each time the button is pressed?
How do I connect similar code to draw a different line that will be triggered when I press a button
To draw on a UIView you have to subclass your UIView
In .h
#MyCustomView : UIView {
}
#end
in .m
#implementation MyCustomView
- (void) drawRect: (CGRect) rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 10, 50);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
In your ViewController
-(void)methodCallCustomView{
}
- (IBAction)draw:(id)sender{
[self methodCallCustomView];
}
So you want the drawRect: method to be called when you press a button? If so, send the message setNeedsDisplay to the view that has the drawRect: code.
so i need to draw 2 different lines. through another posting, i figured out how to redraw a line. my question is, if i want to draw 2 lines do i need to have 2 code segments to do it? or is there a way to draw n lines?
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(#"drawRect called");
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextMoveToPoint(context, self.startPoint.x, self.startPoint.y);
CGContextAddLineToPoint(context, self.endPoint.x, self.endPoint.y);
CGContextStrokePath(context);
}
implementation
draw2D *myCustomView = [[draw2D alloc] init];
myCustomView.startPoint = CGPointMake(0, 0);
myCustomView.endPoint = CGPointMake(300, 300);
myCustomView.lineWidth = 5;
myCustomView.lineColor = [UIColor redColor];
myCustomView.frame = CGRectMake(0, 0, 500, 500);
[myCustomView setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:myCustomView];
[myCustomView setNeedsDisplay];
myCustomView.endPoint = CGPointMake(100, 100);
myCustomView.lineColor = [UIColor orangeColor];
[myCustomView setNeedsDisplay];
this will just redraw the line. do i repeat the drawRect block for each line i want? so if i want two lines, do i have to do:
- (void)drawRect:(CGRect)rect
{
//line1
CGContextRef context1 = UIGraphicsGetCurrentContext();
NSLog(#"drawRect called");
CGContextSetLineWidth(context1, self.lineWidth1);
CGContextSetStrokeColorWithColor(context1, self.lineColor1.CGColor);
CGContextMoveToPoint(context1, self.startPoint1.x, self.startPoint1.y);
CGContextAddLineToPoint(context1, self.endPoint1.x, self.endPoint1.y);
CGContextStrokePath(context1);
//line 2
CGContextRef context2 = UIGraphicsGetCurrentContext();
NSLog(#"drawRect called");
CGContextSetLineWidth(context2, self.lineWidth2);
CGContextSetStrokeColorWithColor(context2, self.lineColor2.CGColor);
CGContextMoveToPoint(context2, self.startPoint2.x, self.startPoint2.y);
CGContextAddLineToPoint(context2, self.endPoint2.x, self.endPoint2.y);
CGContextStrokePath(context2);
}
or is there a better way to handle drawing my lines?
EDIT: the end goal is to use it with a UIView with labels and textboxes i'm using as a form. i want lines to break up the form.
i'm wondering if i should just use these custom draw2D UIViews as lines only and place them on top of the UIView form, then i can just create multiple "draw2D" UIViews?
SOLUTION:
so here is the code i figured out that would work:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
[tempDict setValue:[NSValue valueWithCGPoint:CGPointMake(10, 10)] forKey:#"start"];
[tempDict setValue:[NSValue valueWithCGPoint:CGPointMake(500, 500)] forKey:#"end"];
[tempArray addObject:tempDict];
NSMutableDictionary *tempDict2 = [[NSMutableDictionary alloc] init];
[tempDict2 setValue:[NSValue valueWithCGPoint:CGPointMake(400, 10)] forKey:#"start"];
[tempDict2 setValue:[NSValue valueWithCGPoint:CGPointMake(500, 500)] forKey:#"end"];
[tempArray addObject:tempDict2];
self.pointArray = [NSArray arrayWithArray:tempArray];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
for (int i = 0; i < [self.pointArray count]; i++)
{
CGPoint tempPoint = [[[self.pointArray objectAtIndex:i] objectForKey:#"start"] CGPointValue];
CGPoint tempPoint2 = [[[self.pointArray objectAtIndex:i] objectForKey:#"end"] CGPointValue];
CGContextMoveToPoint(context, tempPoint.x, tempPoint.y);
CGContextAddLineToPoint(context, tempPoint2.x, tempPoint2.y);
}
CGContextStrokePath(context);
}
i included my initWithFrame: method on creating the array that i used for testing (CGPoint's are not objects, so had to figure out how to include them in an dictionary).
so this will loop through and create n lines.
You can just repeat this bit as many times as you need (with different coordinates each time obviously).
CGContextMoveToPoint(context, self.startPoint.x, self.startPoint.y);
CGContextAddLineToPoint(context, self.endPoint.x, self.endPoint.y);
The first line of code sets the start point of the line, the second line of code draws it. You don't need to repeat all the rest of the code.
In other words, you can draw multiple lines like this:
//set up context
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, self.lineWidth1);
CGContextSetStrokeColorWithColor(context, self.lineColor1.CGColor);
//line1
CGContextMoveToPoint(context, self.startPoint1.x, self.startPoint1.y);
CGContextAddLineToPoint(context, self.endPoint1.x, self.endPoint1.y);
//line 2
CGContextMoveToPoint(context, self.startPoint2.x, self.startPoint2.y);
CGContextAddLineToPoint(context, self.endPoint2.x, self.endPoint2.y);
//line 3
etc...
//finished drawing
CGContextStrokePath(context);
You don't need to copy the whole lot each time you draw a line, you can just repeat those two lines of code.
Well, you could refactor out the duplicate code into another method and pass in the variables it needs to draw a line, i.e. the context, colour, start and end points, width
the better and universal way is:
- (void)drawRect:(CGRect)rect:(long)lineWidth:(CGColor)color:(CGPoint)pStart:(CGPoint)pEnd
{
//line1
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(#"drawRect called");
CGContextSetLineWidth(context, lineWidth);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, pStart.x, pStart.y);
CGContextAddLineToPoint(context, pEnd.x, pEnd.y);
CGContextStrokePath(context);
}
...
[self drawRect:rect:self.lineWidth1:self.lineColor1.CGColor:self.startPoint1:self.endPoint1];
[self drawRect:rect:self.lineWidth2:self.lineColor2.CGColor:self.startPoint2:self.endPoint2];
...