How to avoid background erasing when drawing lines? - iphone

I'm writing a paint app.
When drawing a line in CGContext, the background with the size of the bounding box of the line is always got erased - the underlying lines in that box will be cleared.
How to avoid the background erasing?

[EDIT] Better: see How to draw a line on top of an image when finger moves on iPhone. If your image is added as a background specifically, not directly to the view, it will do what you're looking for.
[original] Keep everything you've drawn already, and redraw it in every call to drawRect via setNeedsDisplay.
Or, set your UIView containing the line to UIColor clearColor.

Related

Continuous drawing in CGContext with drawRect

My question might be answered somewhere but I just couldn't find solution after a long research.
I need to draw visually shapes (curves, lines, rectangles etc.) on iPhone one on top of the previous. I did that using CGContext to draw over an image and it's working fine. However in my app the drawing view resizes on device rotation and the lines become blurred because of the different image size.
That's why I subclassed UIView and to call setNeedsDisplay from touchesMoved and touchesEnded. In drawRect I'm passing the point and... almost everything works OK.
However I have two problems:
1. Every time drawRect is called it clears previous drawing and starts over so I can't add a new shape.
2. Second is followed by same thing - I can't make a curve as on every move drawRect is called and the previous point is dismissed and a line is added from the starting point to the current.
So am I doing the whole thing wrong and is there some other better approach to this.
Thanks in advance!

How to erase Drawing Lines on UIView

I drew a line on UIView. It's working properly. I did the same thing as described here : [question]:http://stackoverflow.com/questions/2595446/drawing-an-image-is-completely-out
And now I need to erase those lines. Erase means after I move my finger on the touch screen I need to erase it. Just like an eraser. How can I do it?
If you are asking to erase the whole line when the user touches it, than i don't know how you can achieve that, but if you are asking to erase the part of the line were the user touches, than you can draw a line of the color the view that you are using to draw the line on to in that way you will get the effect of an eraser.
You have to call setNeedsDisplayInRect: (UIView) to set the rectangle of the line as invalid. Only this rectangle will be redrawn until the next drawing cycle.
Make sure you have a flag in the drawRect: method you can ask for, that identifies whether the line should be drawn or not.

iPhone animation with stretchable image

I got a UIView subclass that draws a UIImage as its background. The image is created using the stretchableImageWithLeftCapWidth:topCapHeight: method, it has round edges.
I also use an animation block inside of which I resize my view. I had hoped that during animation, the drawRect:method would get called sometimes, which would result in the background image getting drawn correctly.
Unfortunately, the animation seems to render the image and then just rescale it during the animation, which obviously makes the formerly round edges getting nastily stretched.
The only workaround I can imagine is put three separate UIImageViews (top cap, middle fill, bottom cap) above my original background image and then reposition the caps images and scaling the fill image. However, this seems quite complicated...
Is there any better way I can prevent this from happening?
EDIT: Found this. Sounds bad...
While digging through some Apple docs, I coincidentally found the solution to my problem. All you have to do is play with UIView's contentStretch parameter. It allows you to manually specify the area of your view that gets stretched during animation.

Not drawing outside bounds when clipToBounds=NO

I am drawing lines on a map, and I notice that my annotation view isn't covering the entire area of the lines (which is fine, as long as I can draw outside the bounds of the view).
Here is a picture of what I'm experiencing. The clipToBounds property is set to NO for the annotation view, and I've added a semi-transparent color to the background so you can see the position of the view.
blue line not drawn outside bounds http://img.skitch.com/20100512-qdm18j7x42wptw3cumnr6h271q.jpg
The pins represent the various waypoints on the map.
Do I have to do something special to get the lines to keep drawing outside the bounds of the view?
What lines are you referring to?
Anyway, I think the answer should be "no", unless you are doing custom drawing.
In that case, you need to make sure [view setNeedsDisplay] is being called whenever the lines need to be drawn.

CATiledLayer blanking tiles before drawing contents

All,
I'm having trouble getting behavior that I want from CATiledLayer. Is there a way that I can trigger the tiles to redraw without having the side-effect that their areas are cleared to white first? I've already subclassed CATiledLayer to set fadeDuration to return 0.
To be more specific, here are the details of what I'm seeing and what I'm trying to achieve:
I have a UIScrollView with a big content size...~12000x800. Its content view is a UIView backed by a CATiledLayer.
The UIView is rendered with a lot of custom-drawn lines
Everything works fine, but the contents of the UIView sometimes change. When that happens, I'd like to redraw the tiles as seamlessly as possible. When I use setNeedsDisplay on the view, the tiles redraw but they are first cleared to white and there's a fraction-of-a-second delay before the new content is drawn. I've already subclassed CATiledLayer so that fadeDuration is set to 0.
The behavior that I want seems like it should be possible...when you zoom in on the scrollview and the content gets redrawn at a higher resolution, there's no blanking before the redraw; the new content is drawn right on top of the old one. That's what I'm looking for.
Thanks; I appreciate your ideas.
Update:
Just to follow up - I realized that the tiles weren't being cleared to white before the redraw, they're being taken out entirely; the white that I was seeing is the color of the view that's beneath my CATiledLayer-backed view.
As a quick hack/fix, I put a UIImageView beneath the UIScrollView, and before triggering a redraw of the CATiledLayer-backed view I render its visible section into the UIImageView and let it show. This smooths out the redraw significantly.
If anyone has a better solution, like keeping the redraw-targeted tiles from going away before being redrawn in the first place, I'd still love to hear it.
I've found that if you set levelsOfDetailBias and levelsOfDetail both to the same value (2 in my case), then it only redraws the tiles that are touched by my setNeedsDisplayInRect: call, as you'd hope.
However if the levelsOfDetail is different to LODB, then any calls to setNeedsDisplayInRect: redraw all the tiles.
You could add another layer (possibly a CATiledLayer) behind the existing tiled layer. (Sort of a double-buffered solution.) You would call setNeedsDisplay: on the second layer from a timer that fires after a few seconds to ensure that that layer doesn't redraw at the same time as the front layer.
Another potential option is to use the same delegate to draw content to a bitmap context and swap the bitmap into the backing store once the content is refreshed. This should produce a flicker-free result. That being said, I can't tell you how this might be done, and one nice thing about CATiledLayers is they automatically generate tiles when you zoom and pregenerate tiles when you pan once zoomed in.
I would like to see how you implement your application. I have been looking for weeks to find an example that uses a combination of UIScrollView and a CATiledLayer-back view with a lot of custom drawn lines. Apple has some great sample code - but it all involves images rather than line art, so no help for me.
Having read through these answers without a solution, I discovered that tiling a page was the dominant background task.
Preparing my lo-res placeholder image on a high priority queue solved this issue - the images now appear while the tiling is occurring. Caching the placeholder images further improves their appearance - they appear before the tiling begins.
With newer devices, the tiling it so fast, these tricks might not matter. A sample PDF consisting of large scanned images (e.g. a scanned book) tiles the slowest in my experience, and makes for good test data.
I had the same problem with iPad.
The solution was more simple than I thought and far more simple than using UIImageView to render display before redrawing... :
Just don't set any background color for the Layer!
I had CATiledLayer set in a similar way:
layer = [[CATiledLayer alloc] init];
layer.masksToBounds = YES;
layer.contentsGravity = kCAGravityLeft;
//layer.backgroundColor = [[UIColor whiteColor] CGColor];
layer.tileSize = CGSizeMake(1004.0, 1004.0);
layer.levelsOfDetail = 16;
layer.levelsOfDetailBias = 8;
Note that I have commented out the line setting layer's background color to white.
After that the white blank before redraw problem disappeared!
Let me know if anyone has tried that.