I currently have an UIImage object which gets initialized with initWithFrame and then I have some 2D drawings in -(void)drawRect:(CGRect)rect{} with `CGContext. Very basic. All I want to know is, how can I draw through the push of e.g. a button or any event (not only on initialization)?
I tried copying the code inside drawRect to a new method called redraw but this results in an obvious error:
CGContextMoveToPoint: invalid context 0x0
I only want to know how to be able to draw through CGContext while the UIView has been created. Not e.g. how to listen for an UIButton event
Thank you.
You can only draw inside a UIView's drawRect: method or by creating your own image context. You cannot draw to the screen by any means other than drawRect: or implementing drawing for a CALayer. You need to set variables on your view accordingly, then call setNeedsDisplay to have it redrawn. For example, add a property #property(retain) UIImage *image; to your view, set the new image on it and then call setNeedsDisplay (or even better, implement the setImage: method and call [self setNeedsDisplay]; here).
Related
In a new Single View App, the following code:
- (void)viewDidAppear:(BOOL)animated {
self.fooView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
self.fooView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:self.fooView];
[UIView animateWithDuration:2 animations:^{
self.fooView.backgroundColor = [UIColor blueColor];
}];
}
will animate the yellow background to blue. The fooView is just:
#property (strong, nonatomic) UIView *fooView;
But if a custom view class FooView is defined, and I change the above code above by replacing UIView with FooView, and also define an empty -drawRect for FooView, then there will be no animation -- the background is just changed to blue immediately.
It made no difference if using [UIView animateWithDuration: ...] or [FooView animateWithDuration: ...] -- it is no animation.
If inside -drawRect, I call [super drawRect:rect];, then it is the same thing: no animation.
If I change drawRect to drawRect2, or if I remove the whole method, then the animation will work.
(and the -drawRect might be needed, for example, what if we need to draw a circle in the custom view FooView?)
Why is that? Besides giving a solution of how to make it work even with a -drawRect, please explain what was going on that made it not animate?
The presence of drawRect: changes the way UIView operates. You should only use drawRect: when absolutely necessary and you should never have an empty drawRect: implementation.
If the -drawRect: method is present in your subclass then UIView must do a number of things before it can call this method. Namely, it must allocate a potentially expensive backing store into which your custom drawing will occur, and it must fill this backing store with the background color.
UIView will then call your drawRect: implementation to do any custom drawing on to the backing store, before handing the backing store to the GPU. Only after all that does your animation block begin to run.
So at the start of your animation the backing store that represents your custom UIView has already been painted a new background color.
If your UIView subclass has no drawRect: method then the view has no backing store. The background color is handled directly by the GPU, which can very efficiently animate transitions between colors.
Empty UIView objects (without a drawRect: implementation) are rather lightweight. Your custom view should be composed of multiple subviews depending on what animation effects you want to achieve.
For example, the UITableViewCell class is composed of many subviews. UITableViewCell itself is a UIView. It contains a background view and a selected background view. On top of that is the content view, and inside the content view are various text labels and image views. All of these views combine to produce the selection and resize animations you see in a regular UITableView.
Using 'CATransition' class .You will have to be do animation.
Using this method
+(CAAnimation *)setAnimation{}
Use following line in animation Block
[self.view addSubview:self.fooView];
Instead of this we have to create a new class and using the CATransition and using this class methods '+(CAAnimation *)setAnimation'.We have to create an object for this and call when will transition happen
How can I subclass and draw on an UIImage directly?
I tried extending it and draw on drawAtPoint: or drawInRect: using CoreGraphics, but the image is blank. And neither of the above 2 draw methods are called.
Please don't answer me that I can draw on the UIView because I need a custom runtime designed UIImage.
It's clearly stated in the UIImageView document:
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIImageView_Class/Reference/Reference.html
Subclassing Notes Special Considerations
The UIImageView class is optimized to draw its images to the display.
UIImageView will not call drawRect: a subclass. If your subclass needs
custom drawing code, it is recommended you use UIView as the base
class.
Because telling you to use UIView instead is now allowed, I'll just answer that it's impossible to override drawRect: for UIImageView.
I'm working an app for drawing.
I'm collecting the strokes as points and draw those points into the drawRect method of my UIView subclass.
I collect the point by overriding touchesBegan, touchesMoved and touchesEnded.
In all this those methods I call [self setNeedsDisplay] and i expect to see the strokes in realtime... it doens't happen, acutally the drawRect methods is called only after touchesEnded
I need a way to do not simply mark a view as discarded but i need acutally to force the system to perform the drawRect call.
Any idea ?
Is it possible you're calling setNeedsDisplay on your viewcontroller (self) and not the view (self.view)?
Also you should probably use setNeedsDisplayInRect to only update the part of the view that changes during the touch.
I want to display so many images in table cells. I knew two methods to show an image.
One is creating an instance to UIImageView and show it
CGRect rect=CGRectMake(x,y,width,height);
UIImageView *image=[[UIImageView alloc]initWithFrame:rect];
[image setImage:[UIImage imageNamed:#"sample.jpg"]];
Another method is,
CGRect rect=CGRectMake(x,y,width,height);
[[UIImage imageNamed:#"sample.jpg"] drawInRect:rect];
Now, my question is, what is the difference between these two? Which one is efficient? Or someother function is available better than this?
Thanks in advance....
Using the drawInRect: method has CoreGraphics draw the image into the active CGContext using the CPU. Assuming you're in a UIView's drawRect: method, this will paint the image into the view's buffer.
UIImageView uses whichever image is assigned to it as it's backing buffer instead of using the slower drawRect:. The GPU then references this buffer directly when the screen is composited via QuartzCore.
UIImageView is a UIView subclass. By adding it to the view hierarchy you get all the free benefits: animations, size properties, affine transoforms, etc. Plus, you are able to change the underlying UIImage any time you want.
On the other hand, calling drawInRect: will just draw the image where you tell it to, but not interact with the UIView hierarchy, so you don't gain any of the benefits from having it on the view hierarchy.
I would think (have not tried it), that drawing the image directly is faster, but I would think in most of the cases having a UIImageView is a better idea.
In Iphone development, I want to draw context in layer.
Then the question is:
What exactly is the context passed into drawLayer:inContext:? Is it the layer's contents's context or the UIview's context?
If this is the UIView's context, which UIView it is?
Thanks in advance.
The context being passed in belongs to the CALayer also returned by that delegate method. Usually, this is a display context, but it can also be an image or PDF context if the layer is manually drawn using -renderInContext:.
CALayers can exist on their own, or be used as the backing for a UIView. All UIViews have a layer behind them, which handles the actual display of that view's content. Drawing in a view actually draws on its layer, and, likewise, drawing in a CALayer that backs a UIView will appear to draw to the view.
As I said, you can create CALayers that exist as separate entities, and add them to existing layers as sublayers for display. At some point, there will need to be a UIView that hosts all of these sublayers within its backing layer in order for these layers to be seen on the iPhone's screen.
Note that according to the UIView class reference:
Since the view is the layer’s
delegate, you should never set the
view as a delegate of another CALayer
object. Additionally, you should never
change the delegate of this layer.
This means that for a UIView's layer, you would be handling the delegate method within the UIView in almost all cases, so the layer passed in to that method would be the view's layer. Sublayers can have anything as their delegate, because they are not attached to a particular view.
There is some information here: Providing Layer Content
If you must draw the layer’s content rather than loading it from an image, you implement the drawLayer:inContext: delegate method. The delegate is passed the layer for which content is required and a CGContextRef to draw the content in.
So normally is the context of your delegate object. In the case of UIVIew, the view itself is the delegate.