Redraw outside drawRect function - objective-c

I have a function that draws a rectangle. If called within drawRect image is drawn perfectly. If I call the function directly it doesn't draw the rect. When I searched I found that we need to setNeedsDisplay to Yes. But still it doesn't work.

You can only draw to your window when the system invokes your drawRect: method. You should not call it directly. The system will activate the graphics context before calling drawRect: and perform various housekeeping functions before and after its invocation.
To explicitly request the entire window to be redrawn, you call:
[view setNeedsDisplay:YES];
This will cause your drawRect: method to be called in the next event loop.
The documentation covers all this in detail:
Cocoa Drawing Guide

In such questions the best method is to use a boolean flag. Then call the function inside drawRect: only when the flag is set.
Now when you need the image to be drawn set the flag value to true and then call the [view setNeedsDisplay:YES];
If need be change the flag to false within the if statement once the task has been done.

Related

bar graph project unused method in uiview

I found in git some bar graph project, that I would like to work with: here
The code is pretty simple. The draw object has only 3 methods, like init, calc, and drawRect.
The funny point is, I can not find the line, that call this method: drawRect.
I looked in all the classes. It looks to start automatically, but why? How do I know which methods will start automatically, and which not?
Have you read the Apple Documentation on UIView? It specifically states
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. 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.
So you should never actually call that method directly it will get called by the super versions of setNeedsDisplay or setNeedsDisplayInRect. I have included the whole section of the article below which I would recommend reading.
The default implementation of this method does nothing. Subclasses that use technologies such as Core Graphics and UIKit to draw their view’s content should override this method and implement their drawing code there. You do not need to override this method if your view sets its content in other ways. For example, you do not need to override this method if your view just displays a background color or if your view sets its content directly using the underlying layer object.
By the time this method is called, UIKit has configured the drawing environment appropriately for your view and you can simply call whatever drawing methods and functions you need to render your content. Specifically, UIKit creates and configures a graphics context for drawing and adjusts the transform of that context so that its origin matches the origin of your view’s bounds rectangle. You can get a reference to the graphics context using the UIGraphicsGetCurrentContext function, but do not establish a strong reference to the graphics context because it can change between calls to the drawRect: method.
Similarly, if you draw using OpenGL ES and the GLKView class, GLKit configures the underlying OpenGL ES context appropriately for your view before calling this method (or the glkView:drawInRect: method of your GLKView delegate), so you can simply issue whatever OpenGL ES commands you need to render your content. For more information about how to draw using OpenGL ES, see OpenGL ES Programming Guide for iOS.
You should limit any drawing to the rectangle specified in the rect parameter. In addition, if the opaque property of your view is set to YES, your drawRect: method must totally fill the specified rectangle with opaque content.
If you subclass UIView directly, your implementation of this method does not need to call super. However, if you are subclassing a different view class, you should call super at some point in your implementation.
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. 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.
I got it.
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
So only this one Method will be activated automatically.

using rect argument for drawRect method in custom UIView

How can I possibly use the rect argument passed in drawRect calls, am sure whenever setNeedsDisplayInRect is passed, drawRect method is called for particular region. for now I redraw the text and shapes for entire frame and not constraining to the rect part that needs to be redrawn and I have no idea on how effectively can I use the rect param.
Any insights on this will be helpful.
The rect is the region to redraw. In some cases UIKit will redraw only a "dirty" region of your view. You can optimize your code to detect that some of the drawing would occur outside this rect by using CGRectContainsPoint() and therefore not do it.

setNeedsDisplay does not trigger drawRect in subviews as expected

I'm struggling with setNeedsDisplay. I thought it was supposed to trigger calls of drawRect: for the view for which it is called and the hierarchy below that if it's within the view's bounds, but I'm not finding that to be the case. Here is my setup:
From the application delegate, I create a view whose size is a square that covers essentially the whole screen real estate. This view is called TrollCalendarView. There is not much that happens with TrollCalendarView except for a rotation triggered by the compass.
There are 7 subviews of TrollCalendarView called PlatformView intended to contain 2D draw objects arranged around the center of TrollCalendarView in a 7-sided arrangement. So when the iPad is rotated, these 7 views rotate such that they are always oriented with the cardinal directions.
Each of the PlatformView subviews contains 3 subviews called Tower. Each tower contains 2D draw objects implemented in drawRect:.
So, in summary, I have TrollCalendarView with empty drawRect:, and subviews PlatformView and Platformview -> Tower that each have drawRect implementations. Additionally, Tower lies within the bounds of Platform, and Platform lies within the bounds of TrollCalendarView.
In TrollCalendarView I've added a swipe recognizer. When I swipe happens, a property is updated, and I call [self setNeedsDisplay] but nothing seems to happen. I added NSLog entries to drawRect: method in each of these views, and only the TrollCalendarView drawRect: method is called. Ironically, that is the one view whose drawRect method will be empty.
There is no xib file.
What do I need to do to ensure the drawRect method in the other subviews is called? Is there documentation somewhere that describes all the nuances that could affect this?
I'm struggling with setNeedsDisplay. I thought it was supposed to trigger calls of drawRect for the view for which it is called and the hierarchy below that if it's within the view's bounds
No, that is not the case. Where did you get that idea?
-setNeedsDisplay: applies only to the view to which it is sent. If you need to invalidate other views, you need to add some code to send -setNeedsDisplay: to them, too. That's all there is to it.
I think this is an optimization in the framework; if your subviews don't need to draw again, then this is a major performance improvement. Realize that almost anything animatable does not require drawrect (moving, scaling, etc).
If you know that all of your subviews should be redrawn (and not simply moved), then override setNeedsDisplay in your main view and do like this:
-(void) setNeedsDisplay {
[self.subviews makeObjectsPerformSelector:#selector(setNeedsDisplay)];
[super setNeedsDisplay];
}
I have tested this, and it causes all subviews to be redrawn as well. Please note that you will earn efficiency karma points if you somehow filter your subviews and make sure you only send that to subviews which actually need redrawn... and even more if you can figure out how not to need to redraw them. :-)

UIView setNeedsDisplay calling the CALayer's setNeedsDisplay?

It seems that calling [self setNeedsDisplay] on a UIView does not result in a
[self.layer setNeedsDisplay]. Is it alright if I override setNeedsDisplay as follows:
- (void)setNeedsDisplay {
[super setNeedsDisplay];
[self.layer setNeedsDisplay];
}
Will this get me into trouble? Perhaps there is a better way?
Thank You
I posted this as a comment to another answer, but this may be helpful to other people.
A UIView only calls setNeedsDisplay on its underlying CALayer when drawRect: is implemented (even if the method is empty and does nothing). This tells UIView's setNeedsDisplay that its layer also has some drawing to be done.
Another way to get the layer's setNeedsDisplay to be called automatically is to set the layer's flag needsDisplayOnBoundsChange to true, which will trigger a setNeedsDisplay whenever the view's bounds change (which automatically changes the layer's bounds). But to answer your questions, what you're doing is fine if you didn't override drawRect:, otherwise it's redundant.
I don't see why it would get you into trouble. setNeedsDisplay / setNeedsLayout just flag that the view/layer needs to be displayed / laid out. It'll do the drawing next time around the run loop.
I'm fairly surprised though that calling it on the view doesn't cause it to happen on the layer, because after all a UIView and its associated CALayer are quite tightly integrated.
So overall, yeh if you're finding it's not working for you by just calling setNeedsDisplay on the view then go for your solution. I don't see how it can harm anything.

UIView. How do I redisplay a "data driven" UIView?

I am doing a scientific visualization app for iPhone. Periodically a UIView subclass will receive some data from the network that it must render via its overridden drawRect: method.
My challenge is that there is no way to indicate to Cocoa-Touch that this data has arrived - or changed - other then [myView setNeedsDisplay] which is ignored except for changes to the bounds of the UIView. I have tried hiding and unhiding. Nuthin'.
Maddeningly, since all I did was alter some internal state of the UIView [myView setNeedsDisplay]. This change is completely invisible to Cocoa-Touch. This change is not one of the criteria that warrents a redraw - according to Cocoa-Touch - thus my UIView sits there, unchanged.
This is very, very, very frustrating. I have hit a wall here.
Could someone please suggest a technique, a trick, a hack, that will prompt my UIView to re-render.
Cheers,
Doug
[myView setNeedsDisplay] should cause drawRect: to be sent to myView the next time you're back in the run loop and myView is visible. If changing the bounds is causing the view to redraw (myView.contentMode is UIViewContentModeRedraw), then setNeedsDisplay must be working, since that's how the redraw is signalled by the bounds change. See the UIView class reference for details.
Is your drawRect: being invoked the first time the view is shown? If not, it may be misspelled, overridden in a subclass, or even on the wrong object.
Is the view visible and on screen? It won't be drawn if it is off screen.
Is control returning to the event loop? drawRect: won't be invoked if your application is busy.