how to draw an UIImageView into -drawRect of another view? - iphone

I have several UIImageView objects which have been rotated and scaled. Because they are just background images, and represent an non-highlighted-state, I want to draw them to the canvas of the view so that I can get rid of them in memory. The view has a big bitmap anyways, so it would save a lot of memory to put them in there rather than adding as subview.
It seems I can only call something like -drawInRect for an UIImage, but how about an UIImageView with transforms on it? Oh yes, and it's positioned with frame origin.
I just want to draw it to another UIView's bitmap the same way as it appears when adding as subview.

Using drawInRect: with a rect of different origin and size of the image, you can effectively make any scaling and translation you want. You can also handle rotations with the [CGContextRotateCTM][1] function (CTM = current transformation matrix). There are other CGContext..CTM functions as well, so you have multiple approaches.

Related

Display UIImageView image over it's parent UIImageView

I have an easy task but still don't get how to make it work.
I have a UIView, inside the UIView i have the main UIImageView of half UIView size (half display).
And inside of the UIImageView i have two UIImageViews with images.
I need to pan the internal UIImageViews, and that's not a problem but the problem is that it will not go above the parent UIImageView borders. Same happens when i use two UIImage instead of UIImageView.
I have tried to bring it on top (bringSubviewToFront) but it does not help because its parent controller not the UIView. And the two internal UIImageViews must be a part of the main UIImageView because the main UIImageView can move, so i move all together.
Any help appreciated.
Although the correct solution is to have a superview that's the correct size, you can always "see" what lies outside of the bounds by setting clipsToBounds to NO on the parent UIImageView.
This will draw the subviews even if they lie outside the bounds of the superview. Keep in mind though, that the parts that are outside the bounds will not react to touches, i.e the hit box is always clipped.
You can have one parent view, containing large image and two smaller as siblings. Then you an control position of two images freely without attaching them to larger image.
Like this:
-Parent View (the largest, within which all images aare displayed)
- Large image
- small image
- small image
Now small images are free, and you can align them to large image whenever you want!

How to animate from UiImageView to a UIView

I use Path2.0. I have found that when I click the small picture in a message,there would be an animation to show the whole picture. How does it do that?
I would really appreciate help here. Thanks!
UiImageView is bascially a UIView, which you can apply animation on.
The use case you want to achieve combines:
a. a response to touch event, which you can use UITapGestureRecoginizer to attache a block of code
b. zoom the UIImageView into a proper size and position, you can use UIView's class method AnimiationWithDuration....
c. Ultimately, you want to change your UIImageView's frame property to a larger one. use CGRectMake to generate a new one. If you need to take the whole screen estate (like Path 2.0 does), you may need [UIApplication sharedApplication].window for this
I doubt they modify the original UIImageView; but a solution might be:
Copy the UIImageView (or UIImage)
Add it as a subview with the same exact frame as the original image
Apply a scale transform on the UIImageView (by using the CGAffineTransformMakeScale() function on a UIView's transform property (inside a UIView animation block)
Then instantiate the root window with a scaled version of the full image
Alternatively, you could instantiate the new subview with the full image, set it with the original UIImageView's frame, and then (using a UIView animation block), set it to the newer frame. To match their implementation exactly, I suggest a black subview (of the full UIImageView) with an alpha of 0.0 that you then animate at the same duration to an alpha of 1.0.

Stretchable UIImage and CGAffineTransform

I've got a UIScrollView whose zoom behavior I want to confine to the horizontal axis. I've accomplished that through using a custom UIView as the viewForZoomingInScrollView: and overriding setTransform:. So far so good – the view only zooms horizontally.
One catch: The container view includes some stretchable UIImage instances in UIImageViews. Obviously, with the transform in effect, the images distort.
What's the best bet for either redrawing the view so that the images aren't distorted, or, zooming the view in such a way as to not require transforms in the first place?
Thanks for any help you can offer.
You sure way of achieving this is to make your UIImageView into a custom UIView, and have its drawRect: code do the right thing: draw both stretched and unstretched elements.

how to speed-up drawRect?

I'm coding a map app for iPhone, like Google Maps but with my own maps.
What I have so far is working, but sadly, slower than I would like.
I'm basically drawing the correct map tiles in each drawRect:
[image drawAtPoint:CGPointMake(x, y)];
X and Y are being calculated in each call to drawRect
( these calcs are not very expensive ).
The maximum number of images being drawn at a time is 4.
Each image is 512 x 512.
I feel that some kind of optimization is lacking here.
Can anyone help with something?
Thanks you all.
Why not create UIImageView objects for each tile?
INstead of drawing each image in drawRect, just move the UIIMageView to the correct position in layoutSubviews
The UIImageView will handle drawing when it needs to and will cache it's drawn rect. You're re-rendering each image every time drawRect is called.
The trade-off will probably be more memory consumption as you're making UIImageView objects but you can find a scheme to release ones that aren't being displayed if you need to.
Look for Apple's developer notes on using a tiled scrollview. It may automatically do what you want.

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.