I am trying to draw a line
my Code is this
-(void) drawRect:(CGRect) rect
{
NSLog(#"Reached Draw ARect Function");
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 2.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 2.0, 0, 1);
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint( ctx, 100,100);
CGContextStrokePath(ctx);
}
and i am calling from the viewDidLoad as follows
- (void)viewDidLoad {
[super viewDidLoad];
CGRect k = CGRectMake(1.0, 1.0, 100.0, 200.0);
[self.view drawRect:k];
}
Can any one help me please?
You should subclass a UIView and move your line drawing code to the drawRect: method, like you are doing (just hoping it's for a UIView subclass and not the UIViewController)
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
// Place your code here
}
You must also make sure you use the UIView subclass in InterfaceBuilder for the view you will be drawing into. You should not have to call this method yourself. If you want to animate something you should call the [view setNeedsDisplay]; to request a redraw of the view.
...and...you should add CGContextBeginPath(ctx); just before you call CGContextMoveToPoint
You can't call drawRect directly.
Instead you call setNeedsDisplay on your UIView, return, and wait for the OS to call the UIView's drawRect with a proper context at some later time.
If there is a need to call
- (void)drawRect:(CGRect)rect
method dynamically while user is dragging a particular view, just place the following code:
[self.view setNeedsDisplay];
then
- (void)drawRect:(CGRect)rect
method will automatically be called
Related
So I am trying to override drawRect in my UIScrolLView, however it gives me this black background instead of the background color that I've specified for my UIScrollView. Why is this? If I remove the drawRect code then everything is fine:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if (shouldDrawVerticalLineForProfile){
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef separatorColor = [UIColor colorWithRed:47.0/255.0 green:47.0/255.0
blue:47.0/255.0 alpha:1.0].CGColor;
// Add at bottom
CGPoint startPoint = CGPointMake(60, 0);
CGPoint endPoint = CGPointMake(60, 10000);
CGContextSaveGState(context);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextSetStrokeColorWithColor(context, separatorColor);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
}
I guess what you are searching for is:
myScrollViewInstance.opaque = NO
After that the background of your scroll view should not be black anymore.
I ran into a similar situation when overriding drawRect in my UIScrollView subclass.
Simply overriding with:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
}
resulted in a black background instead of the desired clear background I'd get without overriding.
I found it was because the View Background was set to Default in Interface Builder and that setting it to Clear Color resolved the issue for me.
I'm not sure if this is related to your problem but thought I'd share in case it might help.
The answer here is very clearly documented in the AppleDocs for UIView's drawRect: method. The first sentence is:
The default implementation of this method does nothing.
So, the suggestions here to call super are not going to help. The rest of the answer is contained further down in the discussion:
... if the opaque property of your view is set to YES, your drawRect: method must totally fill the specified rectangle with opaque content.
Meaning that if you don't intend to have a transparent background, you need to actually draw the background. The most correct way to do this is to use the following drawRect: template:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect]; // optional if a direct UIView-subclass, should be called otherwise.
CGContextRef context = UIGraphicsGetCurrentContext();
// Fill the background color, if needed
if (self.opaque) {
UIGraphicsPushContext(context);
CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
CGContextFillRect(context, rect);
UIGraphicsPopContext();
}
// Your code here...
}
Swift Update
Since you are responsible to add background color on your custom view, make sure to fill rect with color:
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else {
return
}
context.saveGState()
// Add you custom color
context.setFillColor(UIColor.white.cgColor)
context.fill(rect)
defer { context.restoreGState() }
// Your custom drawing ....
}
By the way, you could also set your custom view background color on init. Then you do not need to fill rect with color as stated above.
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.white
}
This should help
CGContextSetFillColorWithColor(context, colorBack);
CGContextFillRect(context, self.bounds);
// Choose bounds and colorBack accordingly
Please try this its Work for me
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if (shouldDrawVerticalLineForProfile){
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef separatorColor = [UIColor colorWithRed:47.0/255.0 green:47.0/255.0
blue:47.0/255.0 alpha:1.0].CGColor;
// Add at bottom
CGPoint startPoint = CGPointMake(60, 0);
CGPoint endPoint = CGPointMake(60, 10000);
CGContextSaveGState(context);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextSetStrokeColorWithColor(context, separatorColor);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
}
The only thing that worked for me was to explicitly set the background after any call to setNeedsDisplay. In my example, I was using a subclass of an MKAnnotationView over a map, instead of a UIScrollView, so I don't really know how well this applies to the OP scenario. In my case, I was calling setNeedsDisplay from setAnnotation, and I found that doing so resets by backgroundColor. Simply re-setting by backgroundColor after setNeedsDisplay fixes the problem.
FWIW, I too observed that simply overriding drawRect to delegate to the super class caused this black background problem.
i try to draw arc in view i use this code.
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = CGRectMake(0,0,340,480);
UIView *ui = [[UIView alloc] initWithFrame:rect];
[self.view addSubview:ui];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddArc(context, 50, 50, 20, 0, 30, 0);
//set the fill or stroke color
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1.0);
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
//fill or draw the path
CGContextDrawPath(context, kCGPathStroke);
CGContextDrawPath(context, kCGPathFill);
}
if possible to draw arc in viewdidload method kindly guide me.
Your views should be drawing when requested (e.g. in drawRect:), rather than your view controllers drawing when loaded.
So what you may want to try is creating a UIView subclass and moving the drawing code to its drawRect:.
Very briefly:
#interface MONView : UIView
#end
#implementation MONView
- (void)drawRect:(CGRect)frame
{
CGContextRef context = UIGraphicsGetCurrentContext();
<-- now draw here -->
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = CGRectMake(0,0,340,480);
UIView * ui = [[MONView alloc] initWithFrame:rect];
[self.view addSubview:ui];
[ui release];
}
It is not possible to draw an arc in view Did Load.
What you need to do is:-
1.)Add a file of type UIView(lets say ArcView.h and ArcView.m)in your project
2.)In ArcView.m file implement - (void)drawRect:(CGRect)rect method
3.)In this method you need to write your logic of drawing an arc or whatever you want to draw)
4.)Now the ViewController in which you have to show your arc lets say(ArcViewController is the file in which you want to show your arc)
5.)In ArcViewController.m file you need to do following steps:-
a.)#import "ArcView.h"
b.)Whenever you want to show your arc view do:-
ArcView *vw = [[ArcView alloc] initWithFrame:*your required frame where you want to show arc*];
vw.backgroundColor=[UIColor redColor];
[self.view addSubview:vw];
[vw release];
After that you will see your arc coming on your screen.
I'd like to add shadow to a UIImageView which has image layers.
I've tried self.layer.shadowOffset/shadowOpacity route, but it's too slow..
When I want to add a shadow, I call addShadowLayerWithOffset method below which I expected to call drawRect and add shadow..
But drawRect isn't getting called.
What am I missing here?
- (void)drawRect:(CGRect)rect
{
SYSLOG(LOG_DEBUG, "in drawRect, isShadowed: %d", isShadowed);
if (isShadowed == true)
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetShadow(currentContext, CGSizeMake(100, 100), 3);
[super drawRect: rect];
CGContextRestoreGState(currentContext);
}
else
[super drawRect: rect];
}
- (void) addShadowLayerWithOffset: (int)offset
{
// self.layer.shadowOffset = CGSizeMake(offset,offset);
// self.layer.shadowOpacity = 0.7f;
// self.layer.shadowRadius = 5.0;
isShadowed = true;
[self setNeedsDisplay];
}
EDIT
ok, I got drawLayer being called.
I needed [self.layer setNeedsDisplay] not [self.layer setNeedsPlay] where self is the UIImageView subclass.
But shadow is not being drawn, in fact image(original layer) itself is not shown either.
What should I change?
- (void) drawLayer: (CALayer*) layer inContext: (CGContextRef)context
{
SYSLOG(LOG_DEBUG, "in drawLayer, isShadowed: %d", isShadowed);
if(isShadowed == true)
{
CGContextSaveGState(context);
CGContextSetShadow(context, CGSizeMake(10, 10), 3);
[super drawLayer: layer inContext: context];
CGContextRestoreGState(context);
}
else
[super drawLayer: layer inContext: context];
}
try to call this method:
called by a UIViewController:
[self addShadowedLayer:self.view inRect:( CGRectMake(30, 30, 128, 192))];
- (void)addShadowedLayer:(UIView *)aUIView inRect:(CGRect)aRect {
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
sublayer.shadowOffset = CGSizeMake(0, 3);
sublayer.shadowRadius = 5.0;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shadowOpacity = 0.8;
sublayer.frame = aRect;
sublayer.cornerRadius = 26.0;
[aUIView.layer addSublayer:sublayer];
}
it just add a white rounded rect, but what you need is just its shadow...
you are calling:
[super drawRect: rect];
but apple says:
You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay or setNeedsDisplayInRect: method instead.
instead of drawRect, ever tried drawLayer?
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
I think you are barking up the wrong tree. You said that specifying the shadow directly on the image layer is too slow. That is correct because the OS uses the alpha channel to determine where to draw the shadow.
What you can do to improve the rendering performance on iOS 3.2 and later is that you specify a shadow path. You first create a CGPathRef and set it as the shadow path of the layer.
This should improve rendering dramatically without having you to introduce another layer just for the shadow.
I want to place some "handles" on a UIView I have on-screen.
So, I'm creating more UIViews, one at each corner of the UIView's frame rectangle, and I simply want to draw a circle that "fills" the rectangle that is the frame of the "handle" UIView.
Here's what I mean:
How I create the "HandleView":
CGPoint upperLeft = CGPointMake([[self viewToMove] frame].origin.x - 5, [[self viewToMove] frame].origin.y - 5);
HandleView *uL = [[HandleView alloc] initWithFrame:CGRectMake(upperLeft.x, upperLeft.y, 10, 10)];
[self setUpperLeftHandle:uL];
[uL release];
[[self view] addSubview:[self upperLeftHandle]];
drawRect: for HandleView:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor orangeColor] set];
CGContextFillEllipseInRect(context, [self frame]);
}
What I'm getting is just a set of black rectangles where I place the HandleViews. I'm not sure why they're black, but I can change the color by changing the [HandleView backgroundColor] property. I cannot, though, get anything to DRAW on this view. Calling setNeedsDisplay doesn't seem to make any difference.
Also, the drawRect: method IS being called, so there's a problem with the code there, probably not anywhere else.
It's been a while since I've messed with custom drawing, but I don't remember it being this hard.
What am I missing?
Thanks!!!
Update:
Modified code to this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 100, 100, 100, 1.0);
CGContextFillEllipseInRect(context, rect);
}
Now, I see the circle, but only where it overlays another view. Where it's just sitting on top of the "background" UIView, I get nothing I can see. Also, even though the color is (100, 100, 100), it shows up white/light-light-gray.
What's the deal?
This might work:
- (void)drawRect:(CGRect)rect {
// Drawing code
[[UIColor orangeColor] setFill];
[[UIBezierPath bezierPathWithOvalInRect:rect] fill];
}
The problem is with the following line:
CGContextFillEllipseInRect(context, [self frame]);
You need to change this to the following:
CGContextFillEllipseInRect(context, [self bounds]);
Origin of frame is the left-top corner location of view in the parent. So, it can be any value within the limits of the size of parent view.
So, while drawing with frame, you will be offsetting Fillellipse rect location which happens to be beyond the visible rect of the handle view.
Hence, you were not able to see anything.
As for the color showing up as white, it's because CGContextSetRGBFillColor() expects values from 0.0 to 1.0 for the color component values (not 0-255). So, by passing 100, you were effectively passing 1.0, which was creating a white color.
I would like to write a UIView subclass that, among other things, colors whatever's underneath it a certain color. This is what I've come up with, but it unfortunately doesn't seem to work correctly:
#import <UIKit/UIKit.h>
#class MyOtherView;
#interface MyView : UIView
{
MyOtherView *subview;
}
#end
#implementation MyView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
frame.origin.x += 100.0;
frame.origin.y += 100.0;
frame.size.width = frame.size.height = 200.0;
subview = [[MyOtherView alloc] initWithFrame:frame];
[self addSubview:subview];
[subview release];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// Draw a background to test out on
UIImage *image = [UIImage imageNamed:#"somepic.png"];
[image drawAtPoint:rect.origin];
const CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blueColor] setFill];
rect.size.width = rect.size.height = 200.0;
CGContextFillRect(ctx, rect);
}
#end
#interface MyOtherView : UIView
#end
#implementation MyOtherView
- (void)drawRect:(CGRect)rect
{
// This should tint "MyView" but it doesn't.
const CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeScreen);
[[UIColor redColor] setFill];
CGContextFillRect(ctx, rect);
CGContextRestoreGState(ctx);
}
#end
I want "MyOtherView" to color "MyView" red where it overlaps, but instead it just draws an opaque red block onto it. However, this seems work fine if I copy the -drawRect: function from "MyOtherView" and append it to the one in "MyView" (this took me quite a headache to finally realize). Anyone know what I'm doing wrong? Is it even possible to do this, or should I be approaching it differently?
I think you're over-thinking this. Overlay one view over the other, and set the alpha of the top view to 0.5. You will also need to set opaque to NO.
If you set the background color of the view appropriately, you won't even need to override drawRect.
Might want to check out this SO question.