UIScrollView with multiple zoom levels? - iphone

Is there a way that I can control which subviews of a UIScrollView are scaled and which are not?
For example, I have a map as the bottom layer (not MapKit, just a flat image) which can be zoomed and panned. Depending on user selections, markers are dropped on the map to indicate specific buildings/places etc. These markers are are also UIImageView, using pixel co-ordinates of the map image (eq Building X is at (934, 842), marker is placed here). Zoomed out however these markers are somewhat difficult to see as they also scale/zoom out to the same level as the map.
So is there a way that I can tell the UIScrollView NOT to scale the marker images, but still allow it to pan/reposition them when the map image is zoomed?

I think the method you may be looking for is the UIScrollViewDelegate's
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
This lets you return the view which you want the zoom to be applied to, in your case this will be the background map image.
If you don't want the markers to be scaled at the same time, you will need to add the markers directly as subviews of the UIScrollView, instead of adding them as subviews of your background map UIImageView.
As you mentioned, the markers are placed relatively to the map background UIImageView, this means if you add the markers to the UIScrollView instead, they won't be placed in the same position on the map once you change the scroll.
To solve this, you will need to calculate the equivalent coordinates relative to the UIScrollView.
While this may seem rather daunting, it is actually quite trivial to do once you know the zoom factor.
To get the zoom factor, use the UIScrollViewDelegate method
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
Then you can get the zoom factor by calling :
scrollView.zoomScale
and recalculate the marker coordinates by applying this zoomScale to the original values, and reposition your markers accordingly.
Reference:
UIScrollView Class Reference
UIScrollViewDelegate Protocol Reference
Hope this helps :)

Related

Swift: hot to pan and zomm in/out image inside imageView

In ViewController I have a big ImageView whose image is captured with a ImagePicker. I want the user to be allowed to zoom in/out the image and then pan it but always inside the ImageView dimensions which must not enlarge, move or dwindle. I have seen I could add a ScrollView to ImageView but I can't figure out how to do that.
Moreover: is it possible to zoom in/out more than one ImageView at a time? I mean I have some smaller imageViews floating upon a bigger imageView. Is it possible to zoom everything all together?
There are plenty of excellent scrollview demo's around.
These will show you where and how to add override functions to implement what you need...
If you have different UIImage Views you can set the zoom programmatically to match the image being "zoomed" ... try experimenting with [UIImage].zoomScale. and the image offset. Its going to get complicated if they are different sizes as you will have to take account of scale when mirroring offset and zoom changes.

How to zoom a selected area of image like pupil meter?

I have to show in zoom of a selected area of image continuously. Means if you are changing position simultaneously zoom also to be change. I don't know how to implement this.
UIScrollView has a great method - zoomToRect:animated: - that allows you to zoom on a specific rect. If you have a UIImageView sitting on a UIScrollView then you can zoom around the image view using this one simple method.

Redraw text on zoomed UIImageView after zooming

I have an iOS app which boils down to the following:
A view controller which implements all the UIScrollViewDelegate methods.
A customised UIImageView which is the view returned by viewForZoomingInScrollView in the first view controller.
In the drawRect method of the customised UIImageView I overlay some text at various positions on the image, the text can be at various sizes and angles, constrained by a rectangle defined by points on the image. So the co-ordinate system is all relative to the image associated with the UIImageView.
Sometimes the text is having to be rendered into areas that are far too small to allow the text to be readable at the default zoom level.
When I zoom in, however, this doesn't make the text any more readable as the text was rendered on the original UIImageView at the font size appropriate for the bounds it was given.
What I'd like is some way to redraw this text, in the correct location still, at a proportionally larger font size when zoomed in. Is this possible, and how would I do it?
I've been working on a zoomable floorplan myself and dealt with it in a rather simple way.
I put my text in labels and put those labels on top of the ImageView.
While zooming the labels scale with the UIImageView and thus the text within scale as well.
When zooming in too much however text becomes vague and blurry so you might want to update those text labels in the:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
For me this was sufficient, I hope this might be so for you as well.
Instead of trying to fix this, I'd say your design is a bit wrong. I'd reengineer this so that you're rendering the entire contents that you're displaying in the highest zoom that you want, and then allow the scrollview to zoom in/out of the finished content by specifying the zoom parameters. Otherwise you'll go insane trying to fix text. Just draw the entire image / document as big as you want it to be, then add THOSE contents to the scroll view, at some lower zoom, allowing the user to zoom in/out as they desire. Then you're done.
You can write your overlay text on UILabels, attached to the UIViewController view.
Then you need to make your own custom class from UIScrollView and override
- (void)setContentOffset:(CGPoint)anOffset
here, using the anOffset and self.zoomScale you can place your labels at the places you want, with apropriate font size and all. So, they will change their positions every time your scrollview moves or zooms.

Zooming with a CATiledLayer in a UIScrollView

I'm implementing a map application similar to the maps app and I'm try to add zooming. I have multiple detail levels, e.g. 6, and I want to use the appropriate level for the current zoom scale. I'm using a CATiledLayer in a UIScrollView. So far I can set the min/max zoom in the UIScrollView, drawLayer gets called and I draw the appropriate tile, but this only uses my first map level. Now I want to set levelsOfDetail in the CATiledLayer so I can use the appropriate detail level.
My question is, how do I know at what level I should draw? The tileSize of CATiledLayer is always the same, and so is the clipping rect. I can see when drawLayer gets called for the new level of detail, but how to tell what level that is.
Set the levelsOfDetail and Bias up front. Then when called to draw, look at the frame of the view being zoomed by the scroll view, and compare it against the bounds. That should give you the information needed to determine what you draw. Also look at the clip path bounds to see "where" the CATiledLayer is working on next.

How do I reset (i.e. un-zoom) a UIScrollView?

I have a UIScrollView that contains an image and a segmented control that allows the user to switch the image inside of the ScrollView. If I just swap the image out inside of the UIImageView, it will display the new image in the zoomed-in state. How do I reset the UIScrollView back to its un-zoomed-in state?
I have a detailed discussion of how (and why) UIScrollView zooming works at github.com/andreyvit/ScrollingMadness/.
(The link also contains a description of how to programmatically zoom UIScrollView, how to emulate Photo Library-style paging+zooming+scrolling, an example project and ZoomScrollView class that encapsulates some of the zooming magic.)
Quote:
UIScrollView does not have a notion of a “current zoom level”, because each subview it contains may have its own current zoom level. Note that there is no field in UIScrollView to keep the current zoom level. However we know that someone stores that zoom level, because if you pinch-zoom a subview, then reset its transform to CGAffineTransformIdentity, and then pinch again, you will notice that the previous zoom level of the subview has been restored.
Indeed, if you look at the disassembly, it is UIView that stores its own zoom level (inside UIGestureInfo object pointed to by the _gestureInfo field). It also has a set of nice undocumented methods like zoomScale and setZoomScale:animated:. (Mind you, it also has a bunch of rotation-related methods, maybe we're getting rotation gesture support some day soon.)
However, if we create a new UIView just for zooming and add our real zoomable view as its child, we will always start with zoom level 1.0. My implementation of programmatic zooming is based on this trick.
If you're not redrawing your view on the completion of the pinch zooming event, then the zoom factor is being set by the transform property of the view you return from the viewForZoomingInScrollView: delegate method. To reset this zoom, set the value of the view's transform property to CGAffineTransformIdentity.
Beware, though, that your next pinch-zooming operation will start where the previous pinch-zoom left off (that is, your new scale will be ignored). To work around this, you may need to implement some of what I describe here.