Drawing in Quartz 2D by pushing a button - objective-c

I'm a little bit nooby in Objective-C and I just started working with Quartz 2D. My problem is very simple: I want to draw in Quartz 2D by pressing button. I don't know how I can do that because there are two different classes in my project. I used that tutorial: http://www.techotopia.com/index.php/An_iOS_7_Graphics_Tutorial_using_Core_Graphics_and_Core_Image
Here is my code:
ViewController.h
#interface ViewController : UIViewController
- (IBAction)Start;
ViewController.m
- (IBAction)Start {
}
Draw2D.h
#import <UIKit/UIKit.h>
#interface Draw2D : UIView
#end
Draw2D.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 30, 30);
CGContextAddLineToPoint(context, 300, 400);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context,
[UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddRect(context, rectangle);
CGContextStrokePath(context);
}

If you want to show Draw2D view upon pressing a button, you can add draw2DView as subview of your ViewController:
/// ViewController
- (IBAction)Start:(UIButton *)sender
{
[self.view addSubview:draw2DView];
}
and you should remove these lines in your Draw2D initWithFrame method
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 30, 30);
CGContextAddLineToPoint(context, 300, 400);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
They are below return self; therefore will not be triggered.

Related

Draw lines in UIView not supported for multiple screen sizes?

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.

Create CGImage From CGBitmapContext and Add to UIImageView

I am trying to create a snapshot of a UICollectionViewCell by creating a CGBitMapContext. I am not entirely clear on how to do this or how to use the associated classes, but after a bit of research, I have written the following method which is called from inside my UICollectionViewCell subclass:
- (void)snapShotOfCell
{
float scaleFactor = [[UIScreen mainScreen] scale];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, self.frame.size.width * scaleFactor, self.frame.size.height * scaleFactor, 8, self.frame.size.width * scaleFactor * 4, colorSpace, kCGImageAlphaPremultipliedFirst);
CGImageRef image = CGBitmapContextCreateImage(context);
UIImage *snapShot = [[UIImage alloc]initWithCGImage:image];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.frame];
imageView.image = snapShot;
imageView.opaque = YES;
[self addSubview:imageView];
CGImageRelease(image);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
}
The result is that the image does not appear. Upon debugging, I can determine that I have a valid (non nil) context, CGImage, UIImage and UIImageView, but nothing appears onscreen. Can someone tell me what I am missing?
You can add this as a category to UIView and it will be accessible for any view
- (UIImage*) snapshot
{
UIGraphicsBeginImageContextWithOptions(self.frame.size, YES /*opaque*/, 0 /*auto scale*/);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Then you just need to do [self addSubview:[[UIImageView alloc] initWithImage:self.snapshot]] from you cell object.
[EDIT]
Providing the need for asynchronous rendering (totally understandable) this can be achieved using dispatch queues. I think this would work:
typedef void(^ImageOutBlock)(UIImage* image);
- (void) snapshotAsync:(ImageOutBlock)block
{
CGFloat scale = [[UIScreen mainScreen] scale];
CALayer* layer = self.layer;
CGRect frame = self.frame;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, frame.size.width * scaleFactor, frame.size.height * scaleFactor, 8, frame.size.width * scaleFactor * 4, colorSpace, kCGImageAlphaPremultipliedFirst);
UIGraphicsBeginImageContextWithOptions(frame.size, YES /*opaque*/, scale);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
dispatch_async(dispatch_get_main_queue(), ^() {
block(image);
});
});
}
[EDIT]
- (void) execute
{
__weak typeof(self) weakSelf = self;
[self snapshotAsync:^(UIImage* image) {
[weakSelf addSubview:[[UIImageView alloc] initWithImage:image]]
}];
}

CGContextRef not drawing

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];
}

UITableView with static cell - different separation color per section?

I have UITableView with static cells in 4 sections done in Storyboard. However, I want to change the separator color for one section ([UIColor clearColor]). How can I do that??? Is it actually possible?
I can set the separatorColor to clearColor for the entire table, but not only for one specific section.
Screenshot of table view section:
AFAIK there is no method for this. But you can put a background image to the cell which has a separator at the bottom and set separatorstyle to UITableViewCellSeparatorStyleNone. So you have your own separator in every cell.
Maybe you can achieve your goal by setting the header text for the section to an empty string.
One approach would to create your own UIView subclass and do your own custom drawing in drawRect:. You would take this view and add it as the backgroundView of your table view cell. Something like this:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
// Draw black line
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 0.0, 0.3};
CGColorRef blackColor = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, blackColor);
CGContextMoveToPoint(context, 0, rect.size.height - 1.5);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height - 1.5);
CGContextStrokePath(context);
CGColorRelease(blackColor);
// Draw white bottom line
CGFloat whiteComponents[] = {1.0, 1.0, 1.0, 0.75f};
CGColorRef whiteColor = CGColorCreate(colorspace, whiteComponents);
CGContextSetStrokeColorWithColor(context, whiteColor);
CGContextMoveToPoint(context, 0, rect.size.height - 0.5);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height - 0.5);
CGContextStrokePath(context);
CGColorRelease(whiteColor);
// Draw top white line
CGFloat whiteTransparentComponents[] = {1.0, 1.0, 1.0, 0.45};
CGColorRef whiteTransparentColor = CGColorCreate(colorspace, whiteTransparentComponents);
CGContextSetStrokeColorWithColor(context, whiteTransparentColor);
CGContextMoveToPoint(context, 0, 0.5);
CGContextAddLineToPoint(context, rect.size.width, 0.5);
CGContextStrokePath(context);
CGColorRelease(whiteTransparentColor);
CGColorSpaceRelease(colorspace);
}

Drawing to a view from a function

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.