I am drawing an rectangle using tutorial at here
FlagClass.m
-(void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
}
#end
Then I am adding this view to another view like below
-(IBAction)drawRectangle {
FlagClass *flag = [[FlagClass alloc] initWithFrame:CGRectMake(20.0, 100.0, 80, 40)];
[self.view addSubview:flag];
}
After clicking on the button, what I got is
My question :
These coordinate of my rectangle is (20,100,80,40).What are the numbers in drawRect method
Why I am just getting a black rectangle instead of the blue one with defined coordinates in drawRect
Please help if you have any ideas about it.
Because of the dimensions of your view (the FlagClass instance), all of your drawing is going on outside of the visible bounds (the view is "clipping" the blue rectangle). The black rectangle you're seeing is the default background fill of UIView.
To get what you want, you could adjust the frame of your subview so it's large enough to contain the stroked path. Or change the coordinates you're using to draw; those are the numbers in the calls to CGContextAddLineToPoint. Here's one way to at least see what you're doing (while removing the black background):
FlagClass *flag = [[FlagClass alloc] initWithFrame:CGRectMake(20.0, 100.0, 250, 250)];
flag.backgroundColor = [UIColor clearColor];
[self.view addSubview:flag];
By changing the width and height of the subview (the 3rd and 4th parameters to CGRectMake), the subview becomes large enough to contain the square being drawn.
Related
I want to achieve the effect shown in this github project, but I don't want to use SpriteKit to achieve this.
So I try to draw the big circle in the CircleViiew.m about the CGContextRef in Objective-C.
#import "CircleView.h"
#import <QuartzCore/QuartzCore.h>
#define CIRCLE_RADIUS 80
#implementation CircleView
-(id) initWithFrame:(CGRect)frame andCircleRadius:(int) radius
{
self = [super initWithFrame:frame];
if(self)
{
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// set rect background color
CGRect drawRect = CGRectMake(rect.origin.x, rect.origin.y,rect.size.width, rect.size.height);
CGContextSetRGBFillColor(context, 100.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f, 1.0f);
CGContextFillRect(context, drawRect);
// set line border number
CGContextSetRGBStrokeColor(context,0.6,1,0.6,1.0);
CGContextSetLineWidth(context, 2.0);
CGContextAddArc(context, 82, 82, CIRCLE_RADIUS, 0, 2*M_PI, 0);
CGContextDrawPath(context, kCGPathStroke);
// fill color
UIColor *fillCircleColor = [UIColor colorWithRed:1.000 green:0.800 blue:0.000 alpha:1.000];
CGContextSetFillColorWithColor(context, fillCircleColor.CGColor);
CGContextAddArc(context, 82, 82, CIRCLE_RADIUS, 0, 2*M_PI, 0);
CGContextDrawPath(context, kCGPathFill);
CGContextDrawPath(context, kCGPathFillStroke);
}
#end
Then in the ViewController using the circle.
CircleView *circle = [[CircleView alloc] initWithFrame:CGRectMake(20, 20, 164, 164)];
[self.view addSubview:circle];
But I don't know how to add the small circle overlay the big circle, and the small have to limit on the big circle when we movement the small circle.
Is create small circle object using CircleView on the viewDidload to overlay BigCircle? Or the small circle have to draw in the CircleView class?
I am using auto layout to create the effect. I don't know if I use initwithFrame to make, have generate problem after.
Can anyone give me some direction?
Draw the small circle as a separate view, lying in front of (on top of) the big circle. It can be a UIImageView, for example.
Give the small circle a UIPanGestureRecognizer to make it draggable.
In the gesture recognizer handler, move the view to follow the user's gesture, except that you don't move the view if it would move further than a certain distance from the big circle's center.
I am trying to use CGContextClip() to do some drawing, however I am running into some weird antialiasing problems. The problem appears to be that that the filling is being blended with the colour that it is replacing, instead of the surrounding pixels. See images for a slightly better description of the problem!
Example of issue:
(Note that the blue edge is being antialiased correctly)
Weird antialiased edge:
(Edge should be blended with white, not blue)
Code:
-(void) drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSaveGState(c);
{
CGContextBeginPath(c);
CGContextAddEllipseInRect(c, CGRectMake(25, 25, 200, 200));
CGContextClosePath(c);
CGContextClip(c);
CGContextSetFillColorWithColor(c, [UIColor blueColor].CGColor);
CGContextFillRect(c, rect);
CGContextSetFillColorWithColor(c, [UIColor redColor].CGColor);
CGContextFillRect(c, CGRectMake(0, 0, 250, 125));
}
CGContextRestoreGState(c);
}
Any ideas on how to prevent this weird antialiasing? I can't disable it, as the circle edges still need antialiasing!
Just to be clear, this is simply an example. I am trying to solve this issue on a much more complicated shape, where the solution of only filling half of the clipping to begin with simply isn't possible!
Well, this doesn't 100% fix the problem, but it does reduce the weird antialiasing by a considerable amount. I got the idea from this question. The idea is that you clear any previous rendering in the area where you are going to draw before drawing, by changing the blend mode to clear, performing the drawing and then switching it back to normal and then re-drawing. The modified code looks like this:
-(void) drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSaveGState(c);
{
CGContextBeginPath(c);
CGContextAddEllipseInRect(c, CGRectMake(25, 25, 200, 200));
CGContextClosePath(c);
CGContextClip(c);
CGContextSetFillColorWithColor(c, [UIColor blueColor].CGColor);
CGContextFillRect(c, CGRectMake(25, 25, 200, 200));
CGContextSetFillColorWithColor(c, [UIColor redColor].CGColor);
CGRect r = CGRectMake(0, 0, 250, 125);
CGContextSetBlendMode(c, kCGBlendModeClear);
CGContextFillRect(c, r);
CGContextSetBlendMode(c, kCGBlendModeNormal);
CGContextFillRect(c, r);
}
CGContextRestoreGState(c);
}
If anyone comes up with a better solution that 100% fixes this issue, then post it as an answer and I'll accept it!
I have a label in my view. Now I want to draw a line above the label, which means you can see the label is under the line.
So far I can draw a line using quartz2D but always under the label. Is there any way to solve my problems?
You can create a CAShapeLayer like this:
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.frame = self.label.bounds;
lineLayer.strokeColor = [UIColor redColor].CGColor;
CGRect rect = CGRectMake(0, CGRectGetMidY(lineLayer.bounds), lineLayer.bounds.size.width, 2);
lineLayer.path = [UIBezierPath bezierPathWithRect:rect].CGPath;
And then add it to the UILabel like this:
[self.label.layer addSublayer:lineLayer];
To be honest, the easiest thing to do is to create a 2x2 pixel image called line#2x.png, and have the bottom 2 pixels black, the top 2 transparent, then use it as the background image for an image view. Stretch the image view to whatever width you need by using it as a pattern image. The 1x image should be a 1x1px, all black.
UIView *lineView = [[UIView alloc] initWithFrame:frame]; // Whatever frame the line needs
// Add the line image as a pattern
UIColor *patternColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"line.png"]];
lineView.backgroundColor = patternColor;
[self.view addSubview:lineView];
If this is a label you will be using a lot, you could make a sub-class of UILabel and override the drawRect function.
- (void) drawRect:(CGRect)r
{
[super drawRect:r];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, 1.0, 1.0);
CGContextAddLineToPoint(context, self.bounds.size.width - 1.0, 1.0);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
The advantage here is that the line will be "baked" into the view and only be draw once. Other methods such as CAShapeLayer or UIView will be re-rendered every frame.
For bonus points, you can make the color and line width properties :)
everybody,
I want to make the circle mask on the camera.
i try this way:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddArc(context, self.frame.size.width/2, self.frame.size.height/2, 200, 0, M_PI *2, 0);
//Set the stroke color to black
[[UIColor blackColor]setStroke];
//Define line width and cap
CGContextSetLineWidth(context, 200);
CGContextSetLineCap(context, kCGLineCapButt);
//draw it!
CGContextDrawPath(context, kCGPathStroke);
}
just set the line with enough big,but i think it can set alpha.
thanks.
[[UIColor colorWithRed:0 green:0 blue:0 alpha:alpha/255.0] setStroke];
set the alpha percent you want
As you don't mentioned adjustable circle mask, I assume you need a static circle mask over on the camera view. If you need dynamically created circle, this is not the right answer.
Anyway it might help to know a simple way to do this:
prepare a png which is a circle actually, and the inside of that circle is transparent (make sure you handle the proper width and height or even create multiple circle pngs for different devices eg. iPhone5 and iPhone4)
use the imagePickerController's cameraOverlayView property to add the overlay image
UIView *tmp_camera_overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
UIImageView *tmp_camera_bkgr =[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"circle_screen_overlay.png"]];
tmp_camera_bkgr.frame = CGRectMake(0, 0, 320, 480);
[tmp_camera_overlay addSubview:tmp_camera_bkgr];
imagePickerController.cameraOverlayView = tmp_camera_overlay;
I thought from some point on for OS X, and always true for iOS, that content can appear outside of the view's bounds? (for UIView) But if I create a brand new Single View app, and created a MyView class that subclasses UIView, and implement its drawRect:
- (void)drawRect:(CGRect)rect
{
// Drawing code
UIBezierPath *path = [UIBezierPath bezierPathWithRect:
CGRectMake(-20, -20, 600, 600)];
[[UIColor greenColor] set];
[path fill];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextFillRect(context, CGRectMake(-20, -20, 600, 600));
}
I use both UI and CG to draw a rectangle each, just in case one works and the other doesn't. And the view is added in viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(20, 20, 260, 260)];
[self.view addSubview:myView];
}
But no matter what, the colored box won't go beyond the (20, 20, 260, 260) region. Is it true that only the CALayers can be freely added and appear outside of a view's bounds? Can it be because of the graphics context is limited to this (20, 20, 260, 260) to begin with? If so, is there a way to make drawRect content appear outside of the view's bound, in all four top, down, left, right directions?
Your problem is that "drawRect" is automatically clipped to the view that you are drawing in.
Instead of doing the drawing in the view itself, add a second (sub)view to the first view, that is outside the bounds of the first view. This will allow you to do drawing that is dependent on the placement of the first view, but is outside the first view's bounds.
Hope this helps.
Try this on a view, where you have added the scrollView:
self.scrollView.backgroundColor = [UIColor darkGrayColor];
self.scrollView.layer.cornerRadius = 10.0f;
self.scrollView.layer.masksToBounds = YES;
It should display a gray scrollview with rounded corners, as you want.
Remember you need to import the QuartzCore FrameWork